This commit is contained in:
Johannes Schmelz
2024-11-25 05:33:36 +00:00
parent f67ce6be44
commit d10111d2ab
106 changed files with 4028 additions and 1233 deletions

View File

@@ -34,13 +34,13 @@ public class MonopolyConfig extends Config {
* The width of the game map in terms of grid units.
*/
@Property("map.width")
private int mapWidth = 10;
private int mapWidth = 12;
/**
* The height of the game map in terms of grid units.
*/
@Property("map.height")
private int mapHeight = 10;
private int mapHeight = 12;
/**
* Creates an instance of {@code MonopolyConfig} with default settings.

View File

@@ -0,0 +1,8 @@
package pp.monopoly.game.client;
public class ActiveState extends ClientState{
ActiveState(ClientGameLogic logic) {
super(logic);
}
}

View File

@@ -1,19 +1,11 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.game.client;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.List;
import pp.monopoly.game.server.Player;
import pp.monopoly.message.client.ClientMessage;
import pp.monopoly.message.server.BuyPropertyResponse;
import pp.monopoly.message.server.DiceResult;
@@ -21,6 +13,7 @@ import pp.monopoly.message.server.EventDrawCard;
import pp.monopoly.message.server.GameOver;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.JailEvent;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.message.server.ServerInterpreter;
import pp.monopoly.message.server.TimeOutWarning;
@@ -29,6 +22,7 @@ import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board;
import pp.monopoly.model.IntPoint;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.notification.ClientStateEvent;
import pp.monopoly.notification.GameEvent;
import pp.monopoly.notification.GameEventBroker;
@@ -37,26 +31,30 @@ import pp.monopoly.notification.InfoTextEvent;
import pp.monopoly.notification.Sound;
import pp.monopoly.notification.SoundEvent;
import java.io.File;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.List;
/**
* Controls the client-side game logic for Monopoly.
* Manages the player's placement, interactions with the map, and response to server messages.
* Handles interactions with the server and game state management on the client side.
*/
public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
/** Logger for the client-side game logic. */
static final Logger LOGGER = System.getLogger(ClientGameLogic.class.getName());
/** The object responsible for sending messages to the server. */
private final ClientSender clientSender;
/** A list of listeners to receive game events. */
private final List<GameEventListener> listeners = new ArrayList<>();
/** The game board representing the player's current state. */
private Board board;
private ClientState state = new ClientState(this) {
};
/** The current state of the client game logic. */
private ClientState state = new LobbyState(this);
private List<Player> players;
private BoardManager boardManager = new BoardManager();
/**
* Constructs a ClientGameLogic with the specified sender object.
@@ -67,8 +65,18 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
this.clientSender = clientSender;
}
/**
* Reutns the BoardManager
* @return the boardManager
*/
public BoardManager getBoardManager() {
return boardManager;
}
/**
* Returns the current state of the game logic.
*
* @return the current state
*/
ClientState getState() {
return state;
@@ -86,10 +94,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.entry();
}
public List<Player> getPlayers() {
return players;
}
/**
* Returns the player's own map.
* Returns the player's game board.
*
* @return the player's own map
* @return the player's game board
*/
public Board getBoard() {
return board;
@@ -116,32 +128,24 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
/**
* Emits an event to play the specified sound.
*
* @param sound the sound to be played.
* @param sound the sound to be played
*/
public void playSound(Sound sound) {
notifyListeners(new SoundEvent(sound));
}
/**
* Loads a map from the specified file.
*
* @param file the file to load the map from
* @throws IOException if an I/O error occurs
*/
public void loadMap(File file) throws IOException {
state.loadMap(file);
}
/**
* Sends a message to the server.
*
* @param msg the message to be sent
*/
void send(ClientMessage msg) {
if (clientSender == null)
public void send(ClientMessage msg) {
if (clientSender == null) {
LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS
else
} else {
clientSender.send(msg);
System.out.println("Message gesendet");
}
}
/**
@@ -173,12 +177,13 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
synchronized (this) {
copy = new ArrayList<>(listeners);
}
for (GameEventListener listener : copy)
for (GameEventListener listener : copy) {
event.notifyListener(listener);
}
}
/**
* Called once per frame by the update loop.
* Updates the game logic once per frame in the update loop.
*
* @param delta time in seconds since the last update call
*/
@@ -186,6 +191,11 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
state.update(delta);
}
/**
* Handles the response for buying a property.
*
* @param msg the message containing the buy property response
*/
@Override
public void received(BuyPropertyResponse msg) {
if (msg.isSuccessful()) {
@@ -195,35 +205,66 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
setInfoText("Unable to buy " + msg.getPropertyName() + ". Reason: " + msg.getReason());
}
}
/**
* Handles the result of a dice roll.
*
* @param msg the message containing the dice roll result
*/
@Override
public void received(DiceResult msg) {
setInfoText("You rolled a " + msg.calcTotal() + "!");
//Set the dice images
playSound(Sound.DICE_ROLL);
}
/**
* Handles drawing an event card.
*
* @param msg the message containing the drawn card details
*/
@Override
public void received(EventDrawCard msg) {
setInfoText("Event card drawn: " + msg.getCardDescription());
// Kartenlogik
playSound(Sound.EVENT_CARD);
}
/**
* Handles the game over message.
*
* @param msg the message containing game over details
*/
@Override
public void received(GameOver msg) {
if (msg.isWinner()) {
setInfoText("Congratulations! You have won the game!");
//Winner popup
playSound(Sound.WINNER);
} else {
setInfoText("Game over. Better luck next time!");
// Looser popup
playSound(Sound.LOSER);
}
}
/**
* Handles the start of the game.
*
* @param msg the game start message
*/
@Override
public void received(GameStart msg) {
players = msg.getPlayers();
setInfoText("The game has started! Good luck!");
setState(new WaitForTurnState(this));
}
/**
* Handles jail-related events.
*
* @param msg the message containing jail event details
*/
@Override
public void received(JailEvent msg) {
if (msg.isGoingToJail()) {
@@ -233,28 +274,74 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
setInfoText("You are out of jail!");
}
}
/**
* Updates the status of a player.
*
* @param msg the message containing player status update details
*/
@Override
public void received(PlayerStatusUpdate msg) {
setInfoText("Player " + msg.getPlayerName() + " status updated: " + msg.getStatus());
}
/**
* Handles timeout warnings.
*
* @param msg the message containing timeout warning details
*/
@Override
public void received(TimeOutWarning msg) {
setInfoText("Warning! Time is running out. You have " + msg.getRemainingTime() + " seconds left.");
}
/**
* Displays the player's assets in response to a server query.
*
* @param msg the message containing the player's assets
*/
@Override
public void received(ViewAssetsResponse msg) {
setInfoText("Your current assets are being displayed.");
}
/**
* Handles trade replies from other players.
*
* @param msg the message containing the trade reply
*/
@Override
public void received(TradeReply msg) {
if (msg.getTradeHandler().getStatus()) {
setInfoText("Trade accepted by " + msg.getTradeHandler().getReceiver().getName() + ".");
playSound(Sound.TRADE_ACCEPTED);
} else {
setInfoText("Trade rejected by " + msg.getTradeHandler().getReceiver().getName() + ".");
playSound(Sound.TRADE_REJECTED);
}
}
/**
* Handles trade requests from other players.
*
* @param msg the message containing the trade request details
*/
@Override
public void received(TradeRequest msg) {
setInfoText("Trade offer received from " + msg.getTradeHandler().getSender().getName());
// playSound(Sound.TRADE_REQUEST); no sound effect
// notifyListeners();
}
/**
* Handles the transition to the next player's turn.
*
* @param msg the message indicating it's the next player's turn
*/
@Override
public void received(NextPlayerTurn msg) {
setInfoText("It's your turn!");
setState(new ActiveState(this));
}
}

View File

@@ -0,0 +1,8 @@
package pp.monopoly.game.client;
public class LobbyState extends ClientState{
LobbyState(ClientGameLogic logic) {
super(logic);
}
}

View File

@@ -0,0 +1,8 @@
package pp.monopoly.game.client;
public class WaitForTurnState extends ClientState{
WaitForTurnState(ClientGameLogic logic) {
super(logic);
}
}

View File

@@ -10,10 +10,12 @@ package pp.monopoly.game.server;
import java.util.List;
import java.util.Random;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.message.server.DiceResult;
import pp.monopoly.model.FieldVisitor;
import pp.monopoly.model.Figure;
import pp.monopoly.model.card.DeckHelper;
import pp.monopoly.model.card.Card;
import pp.monopoly.model.fields.BuildingProperty;
import pp.monopoly.model.fields.EventField;
import pp.monopoly.model.fields.FineField;
@@ -28,11 +30,11 @@ import pp.monopoly.model.fields.WacheField;
/**
* Class representing a player
*/
@Serializable
public class Player implements FieldVisitor<Void>{
private final int id;
private String name;
private PlayerColor color;
private int accountBalance = 0;
private int accountBalance = 15000;
private Figure figure;
private List<PropertyField> properties;
private int getOutOfJailCard;
@@ -41,6 +43,14 @@ public class Player implements FieldVisitor<Void>{
private final PlayerHandler handler;
private PlayerState state = new LobbyState();
/**
* Default constructor for serialization purposes.
*/
private Player(){
id = 0;
handler = null;
}
/**
* Constructs a player with the speciefied params
* @param id the id of the player
@@ -63,20 +73,38 @@ public class Player implements FieldVisitor<Void>{
this.handler = handler;
}
public void setFigure(Figure figure) {
this.figure = figure;
}
public PlayerColor getColor() {
switch ((id%6)+1) {
case 1: return PlayerColor.BLUE;
case 2: return PlayerColor.GREEN_DARK;
case 3: return PlayerColor.GREEN_LIGHT;
case 4: return PlayerColor.PINK;
case 5: return PlayerColor.RED;
case 6: return PlayerColor.YELLOW;
default:
return null;
}
}
/**
* Set the name of the Player
* @param name the new name
*/
void setName(String name) {
public void setName(String name) {
this.name = name;
}
/**
* Set the PlayerColor
* @param color the color to be set to
* Retuns the Playerhandler
* @return the Playerhandler
*/
void setColor(PlayerColor color) {
this.color = color;
public PlayerHandler getHandler() {
return handler;
}
/**
@@ -94,6 +122,21 @@ public class Player implements FieldVisitor<Void>{
public int getFieldID() {
return fieldID;
}
void setActive() {
state = new ActiveState();
}
boolean finishTurn() {
if(canFinishTurn()) {
state = new WaitForTurnState();
return true;
}
else return false;
}
boolean canFinishTurn() {
return accountBalance >= 0;
}
/**
* Moves by the specified amount of steps
@@ -115,9 +158,11 @@ public class Player implements FieldVisitor<Void>{
fieldID = fieldID%40;
earnMoney(2000);
}
figure.moveTo(fieldID);
return fieldID;
}
/**
* Gets all the properties owned by this player
* @return List of all properties owned by this player
@@ -134,6 +179,7 @@ public class Player implements FieldVisitor<Void>{
public void buyProperty(PropertyField property) {
if (property.getOwner() == null && accountBalance >= property.getPrice()) {
properties.add(property);
property.setOwner(this);
pay(property.getPrice());
}
}
@@ -149,6 +195,14 @@ public class Player implements FieldVisitor<Void>{
}
}
/**
* Set the account Balance
* @param accountBalance the amount to be set to
*/
public void setAccountBalance(int accountBalance) {
this.accountBalance = accountBalance;
}
/**
* Gets this players current accountBalanece
* @return the amount of money currently owned by this player
@@ -264,7 +318,8 @@ public class Player implements FieldVisitor<Void>{
@Override
public Void visit(EventField field) {
DeckHelper.drawCard();
Card c = getHandler().getLogic().getDeckHelper().drawCard();
getHandler().getLogic().getDeckHelper().visit(c, this);
return null;
}
@@ -307,7 +362,27 @@ public class Player implements FieldVisitor<Void>{
return count;
}
/**
public int getNumHouses() {
int total = 0;
for (PropertyField field : properties) {
if (field.getClass() == BuildingProperty.class) {
total += ((BuildingProperty) field).getHouses();
}
}
return total;
}
public int getNumHotels() {
int total = 0;
for (PropertyField field : properties) {
if (field.getClass() == BuildingProperty.class) {
total += ((BuildingProperty) field).getHotel();
}
}
return total;
}
/**
* Inner class for dice functionality in the game.
* Rolls random dice values.
*/
@@ -440,47 +515,19 @@ public class Player implements FieldVisitor<Void>{
}
}
private class BankruptState implements PlayerState {
@Override
public DiceResult rollDice() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
}
@Override
public void payBail() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'payBail'");
}
@Override
public void useJailCard() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
}
}
private class WaitForTurnState implements PlayerState {
@Override
public DiceResult rollDice() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'rollDice'");
throw new UnsupportedOperationException("not allowed");
}
@Override
public void payBail() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'payBail'");
}
@Override
public void useJailCard() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'useJailCard'");
}
}

View File

@@ -2,17 +2,30 @@ package pp.monopoly.game.server;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.model.LimitedLinkedList;
/**
* A class for helping with player actions and managing thier turns
*/
@Serializable
public class PlayerHandler {
private List<Player> players = new LinkedList<>();
private List<Player> players = new LimitedLinkedList<>(6);
private Set<Player> readyPlayers = new HashSet<>();
private ServerGameLogic logic;
private Player hostPlayer;
private Player extra = null;
/**
* Default constructor for serialization purposes.
*/
private PlayerHandler() {}
/**
* Contructs a PlayerHandler
@@ -42,6 +55,14 @@ public class PlayerHandler {
players.addAll(players);
}
/**
* Return the host player
* @return the host player
*/
public Player getHostPlayer() {
return hostPlayer;
}
/**
* Return the number of players
* @return number of players in the game
@@ -50,6 +71,14 @@ public class PlayerHandler {
return players.size();
}
/**
* Retuns all players
* @return List of all players
*/
public List<Player> getPlayers() {
return players;
}
/**
* Chechs if all players are ready to start the game
* @return {@code true} if all players are ready, otherwise {@code false}
@@ -85,6 +114,9 @@ public class PlayerHandler {
throw new IllegalArgumentException("Player already registered");
}
players.add(player);
if(hostPlayer == null) {
hostPlayer = player;
}
}
/**
@@ -108,8 +140,13 @@ public class PlayerHandler {
* Completes a player turn and return the next player
* @return the next players who is active
*/
Player nextPlayer() {
public Player nextPlayer() {
Player tmp = players.get(0);
if (extra != null) {
tmp = extra;
extra = null;
return tmp;
}
players.remove(0);
players.add(tmp);
return players.get(0);
@@ -119,7 +156,7 @@ public class PlayerHandler {
* Returns the {@link ServerGameLogic} of this PlayerHandler
* @return the {@link ServerGameLogic} of this PlayerHandler
*/
ServerGameLogic getLogic() {
public ServerGameLogic getLogic() {
return logic;
}
@@ -128,10 +165,32 @@ public class PlayerHandler {
* @param id the id to be searched for
* @return the player with the required id
*/
Player getPlayerById(int id) {
public Player getPlayerById(int id) {
for (Player player : players) {
if (player.getId() == id) return player;
}
throw new NoSuchElementException("Player mit id "+id+" existiert nicht");
}
/**
* Arranges the players turns in a random order.
* Shuffles the players and sets their state to WaitForNextTurn, the first one will be active
*/
void randomOrder() {
Collections.shuffle(players);
for (Player player : players) {
player.finishTurn();
}
players.get(0).setActive();
}
public void setStartBalance(int amount) {
for (Player player : players) {
player.setAccountBalance(amount);
}
}
public void extraTurn(Player player) {
if (players.contains(player)) extra = player;
}
}

View File

@@ -1,20 +1,30 @@
package pp.monopoly.game.server;
import pp.monopoly.MonopolyConfig;
import pp.monopoly.message.client.*;
import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import pp.monopoly.MonopolyConfig;
import pp.monopoly.message.client.BuyPropertyRequest;
import pp.monopoly.message.client.ClientInterpreter;
import pp.monopoly.message.client.EndTurn;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.message.client.RollDice;
import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.message.server.GameStart;
import pp.monopoly.message.server.NextPlayerTurn;
import pp.monopoly.message.server.PlayerStatusUpdate;
import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.model.Board;
import pp.monopoly.model.Figure;
import pp.monopoly.model.Rotation;
import pp.monopoly.model.card.DeckHelper;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField;
/**
* Controls the server-side game logic for Monopoly.
@@ -26,9 +36,11 @@ public class ServerGameLogic implements ClientInterpreter {
private final MonopolyConfig config;
private final PlayerHandler playerHandler = new PlayerHandler(this);
private final ServerSender serverSender;
private ServerState state = ServerState.CREATEGAME;
private ServerState state = ServerState.LOBBY;
private static final int MAX_PLAYERS = 6;
private BoardManager boardManager = new BoardManager();
private final DeckHelper deckHelper = new DeckHelper();
private int startMoney;
/**
* Constructs a ServerGameLogic instance with the specified sender and configuration.
@@ -120,6 +132,7 @@ public class ServerGameLogic implements ClientInterpreter {
playerHandler.addPlayer(player);
LOGGER.log(Level.DEBUG, "Player added: {0}", player.getId());
System.out.println("Anzahl Spieler verbunden:"+ playerHandler.getPlayerCount());
return player;
}
@@ -158,8 +171,12 @@ public class ServerGameLogic implements ClientInterpreter {
public void received(EndTurn msg, int from) {
Player player = playerHandler.getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
playerHandler.nextPlayer();
if (player.finishTurn()) {
LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
Player next = playerHandler.nextPlayer();
next.setActive();
send(next, new NextPlayerTurn(next));
}
}
}
@@ -172,12 +189,26 @@ public class ServerGameLogic implements ClientInterpreter {
@Override
public void received(PlayerReady msg, int from) {
Player player = playerHandler.getPlayerById(from);
if(player == playerHandler.getHostPlayer()) {
startMoney = msg.getStartMoney();
}
if (player != null) {
player.setName(msg.getName());
player.setColor(msg.getColor());
player.setName(msg.getName());
player.setFigure(new Figure(1, -10, -10, Rotation.LEFT, msg.getFigure()));
//TODO add figure to the map
playerHandler.setPlayerReady(player, true);
LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName());
}
if(playerHandler.allPlayersReady()) {
playerHandler.setStartBalance(startMoney);
for (Player p : playerHandler.getPlayers()) {
send(p, new GameStart(playerHandler.getPlayers()));
}
playerHandler.randomOrder();
send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn(playerHandler.getPlayerAtIndex(0)));
}
}
/**
@@ -236,11 +267,12 @@ public class ServerGameLogic implements ClientInterpreter {
*/
@Override
public void received(ViewAssetsRequest msg, int from) {
Player player = playerHandler.getPlayerById(from);
if (player != null) {
LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", player.getName());
Player sender = playerHandler.getPlayerById(from);
Player player = msg.getPlayer();
if (sender != null && player != null) {
LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", sender.getName());
send(player, new ViewAssetsResponse(player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
send(sender, new ViewAssetsResponse(boardManager, player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
}
}
@@ -256,4 +288,8 @@ public class ServerGameLogic implements ClientInterpreter {
public Player getPlayerById(int id) {
return playerHandler.getPlayerById(id);
}
public DeckHelper getDeckHelper() {
return deckHelper;
}
}

View File

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

View File

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

View File

@@ -1,49 +1,51 @@
package pp.monopoly.message.client;
import pp.monopoly.game.server.PlayerColor;
import com.jme3.network.serializing.Serializable;
/**
* Represents a message indicating the player is ready to play.
*/
public class PlayerReady extends ClientMessage{
@Serializable
public class PlayerReady extends ClientMessage {
private boolean isReady;
private String name;
private PlayerColor color;
private String figure;
private int startMoney;
/**
* Default constructor for serialization purposes.
*/
private PlayerReady() { /* empty */ }
/**
* Constructs a PlayerReady message.
*
* @param isReady true if the player is ready, false otherwise
* @param name the name of the player
* @param color the color of the player (can be null)
*/
public PlayerReady(boolean isReady) {
public PlayerReady(boolean isReady, String name, String figure, int startMoney) {
this.isReady = isReady;
this.name = name;
this.figure = figure;
this.startMoney = startMoney;
}
/**
* Getter for the Name
* @return the Name
*/
public String getName() {
return name;
}
/**
* Getter for the Playercolor
* @return the Playercolor
*/
public PlayerColor getColor() {
return color;
public String getFigure() {
return figure;
}
/**
* Checks if the player is ready.
*
* @return true if ready, false otherwise
*/
public boolean isReady() {
return isReady;
}
public int getStartMoney() {
return startMoney;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,33 @@
package pp.monopoly.message.client;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player;
/**
* Represents a request from a player to view their assets.
*/
@Serializable
public class ViewAssetsRequest extends ClientMessage{
private Player player;
/**
* Default constructor for serialization purposes.
*/
private ViewAssetsRequest() { /* empty */ }
public ViewAssetsRequest(Player player) {
this.player = player;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {
interpreter.received(this, from);
}
public Player getPlayer() {
return player;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,29 @@
package pp.monopoly.message.server;
import java.util.List;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player;
@Serializable
public class GameStart extends ServerMessage{
private List<Player> players;
/**
* Default constructor for serialization purposes.
*/
private GameStart() { /* empty */ }
public GameStart(List<Player> players) {
this.players = players;
}
public List<Player> getPlayers() {
return players;
}
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);

View File

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

View File

@@ -0,0 +1,36 @@
package pp.monopoly.message.server;
import com.jme3.network.serializing.Serializable;
import pp.monopoly.game.server.Player;
@Serializable
public class NextPlayerTurn extends ServerMessage{
private Player player;
/**
* Default constructor for serialization purposes.
*/
private NextPlayerTurn() { /* empty */ }
public NextPlayerTurn(Player player) {
this.player = player;
}
@Override
public void accept(ServerInterpreter interpreter) {
interpreter.received(this);
}
@Override
public String getInfoTextKey() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
}
public Player getPlayer() {
return player;
}
}

View File

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

View File

@@ -89,4 +89,11 @@ public interface ServerInterpreter {
* @param msg the TradeRequest message received
*/
void received(TradeRequest msg);
/**
* Handles a NextPlayerTurn message received from the server.
*
* @param msg the NextPlayerTurn message received
*/
void received(NextPlayerTurn msg);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,7 +57,6 @@ public class Board {
this.width = width;
this.height = height;
this.eventBroker = eventBroker;
addItem(new Figure(5, 5, 5, Rotation.LEFT));
}
/**

View File

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

View File

@@ -4,35 +4,18 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.jme3.network.serializing.Serializable;
import static java.lang.Math.max;
import static java.lang.Math.min;
@Serializable
public class Figure implements Item{
/**
* Enumeration representing the different statuses a Figure can have during the game.
*/
public enum Status {
/**
* The ship is in its normal state, not being previewed for placement.
*/
NORMAL,
/**
* The ship is being previewed in a valid position for placement.
*/
VALID_PREVIEW,
/**
* The ship is being previewed in an invalid position for placement.
*/
INVALID_PREVIEW
}
private final String type;
private final int length; // The length of the Figure
private int x; // The x-coordinate of the Figure's position
private int y; // The y-coordinate of the Figure's position
private Rotation rot; // The rotation of the Figure
private Status status; // The current status of the Figure
private final Set<IntPoint> damaged = new HashSet<>(); // The set of positions that have been hit on this ship
/**
@@ -40,7 +23,7 @@ public class Figure implements Item{
* at position (0, 0), with a default rotation of RIGHT.
*/
private Figure() {
this(0, 0, 0, Rotation.RIGHT);
this(0, 0, 0, Rotation.RIGHT, "cube");
}
/**
@@ -51,12 +34,12 @@ public class Figure implements Item{
* @param y the y-coordinate of the Figure's initial position
* @param rot the rotation of the Figure
*/
public Figure(int length, int x, int y, Rotation rot) {
public Figure(int length, int x, int y, Rotation rot, String type) {
this.x = x;
this.y = y;
this.rot = rot;
this.length = length;
this.status = Status.NORMAL;
this.type = type;
}
/**
@@ -87,7 +70,7 @@ public class Figure implements Item{
this.x = x;
this.y = y;
}
/**
* Moves the Figure to the specified position.
*
@@ -98,21 +81,46 @@ public class Figure implements Item{
}
/**
* Returns the current status of the Figure.
* Moves the Figure to the specified coordinates.
*
* @return the status of the Figure
* @param x the new x-coordinate of the Figure's position
* @param y the new y-coordinate of the Figure's position
*/
public Status getStatus() {
return status;
public void moveTo(int fieldId) {
moveTo(fieldIdToPosition(fieldId));
}
/**
* Sets the status of the Figure.
*
* @param status the new status to be set for the Figure
*/
public void setStatus(Status status) {
this.status = status;
private IntPoint fieldIdToPosition(int fieldId) {
if (fieldId < 0 || fieldId > 39) {
throw new IllegalArgumentException("Invalid fieldId: " + fieldId);
}
// Determine which edge and position along the edge
if (fieldId <= 9) {
// Bottom edge: From (-10, -10) to (10, -10)
int x = -10 + fieldId * 2;
return new IntPoint(x, -10);
} else if (fieldId <= 19) {
// Right edge: From (10, -10) to (10, 10)
int y = -10 + (fieldId - 10) * 2;
return new IntPoint(10, y);
} else if (fieldId <= 29) {
// Top edge: From (10, 10) to (-10, 10)
int x = 10 - (fieldId - 20) * 2;
return new IntPoint(x, 10);
} else {
// Left edge: From (-10, 10) to (-10, -10)
int y = 10 - (fieldId - 30) * 2;
return new IntPoint(-10, y);
}
}
private Rotation fieldIdToRotation(int fieldId) {
if (fieldId >= 0 && fieldId <= 10) return Rotation.DOWN;
else if (fieldId <= 20) return Rotation.LEFT;
else if (fieldId <= 30) return Rotation.UP;
else if (fieldId <= 39) return Rotation.RIGHT;
else throw new IllegalArgumentException();
}
/**

View File

@@ -0,0 +1,57 @@
package pp.monopoly.model;
import java.util.LinkedList;
import com.jme3.network.serializing.Serializable;
/**
* A LinkedList with a maximum size limit.
*
* @param <E> the type of elements held in this collection
*/
@Serializable
public class LimitedLinkedList<E> extends LinkedList<E> {
private int maxSize;
/**
* Default constructor for serialization purposes.
*/
private LimitedLinkedList() {}
/**
* Constructs a LimitedLinkedList with the specified maximum size.
*
* @param maxSize the maximum number of elements this list can hold
*/
public LimitedLinkedList(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("Max size must be greater than 0");
}
this.maxSize = maxSize;
}
/**
* Adds an element to the list. If the list exceeds its maximum size,
* the oldest element (first) is removed.
*
* @param element the element to be added
* @return true if the element was added successfully
*/
@Override
public boolean add(E element) {
if (size() >= maxSize) {
return false;
}
return super.add(element);
}
/**
* Gets the maximum size of this list.
*
* @return the maximum size
*/
public int getMaxSize() {
return maxSize;
}
}

View File

@@ -6,66 +6,112 @@ import pp.monopoly.model.fields.PropertyField;
import java.util.List;
/**
* Helper class that handles the trade logic between two players.
* Manages trade initiation, validation, acceptance, and rejection involving multiple properties, money, and jail cards.
* Handles a single trade between two players.
* Encapsulates trade details, validation, acceptance, and rejection.
*/
public class TradeHandler {
private final Player sender;
private final Player receiver;
private final int offeredAmount;
private final List<PropertyField> offeredProperties;
private final int offeredJailCards;
private final int requestedAmount;
private final List<PropertyField> requestedProperties;
private final int requestedJailCards;
private Boolean status = null;
/**
* Initiates a trade offer between two players involving properties, money, and jail cards.
* Constructs a TradeHandler for a single trade instance.
*
* @param sender the Player who is initiating the trade
* @param receiver the Player who is the target of the trade offer
* @param offeredAmount the amount of money the sender offers
* @param offeredProperties the list of properties the sender offers
* @param offeredJailCards the number of jail cards the sender offers
* @param requestedAmount the amount of money the sender requests from the receiver
* @param requestedProperties the list of properties the sender requests from the receiver
* @param requestedJailCards the number of jail cards the sender requests from the receiver
* @return true if the trade offer is valid and initiated, false otherwise
* @param sender the Player initiating the trade
* @param receiver the Player receiving the trade offer
* @param offeredAmount the amount of money offered by the sender
* @param offeredProperties the properties offered by the sender
* @param offeredJailCards the jail cards offered by the sender
* @param requestedAmount the amount of money requested from the receiver
* @param requestedProperties the properties requested from the receiver
* @param requestedJailCards the jail cards requested from the receiver
*/
public boolean initiateTrade(Player sender, Player receiver, int offeredAmount, List<PropertyField> offeredProperties,
int offeredJailCards, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
// Validate the trade offer
if (!validateTrade(sender, offeredAmount, offeredProperties, offeredJailCards, receiver, requestedAmount, requestedProperties, requestedJailCards)) {
public TradeHandler(Player sender, Player receiver, int offeredAmount, List<PropertyField> offeredProperties,
int offeredJailCards, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
this.sender = sender;
this.receiver = receiver;
this.offeredAmount = offeredAmount;
this.offeredProperties = offeredProperties;
this.offeredJailCards = offeredJailCards;
this.requestedAmount = requestedAmount;
this.requestedProperties = requestedProperties;
this.requestedJailCards = requestedJailCards;
}
public int getOfferedAmount() {
return offeredAmount;
}
public int getOfferedJailCards() {
return offeredJailCards;
}
public List<PropertyField> getOfferedProperties() {
return offeredProperties;
}
public Player getReceiver() {
return receiver;
}
public int getRequestedAmount() {
return requestedAmount;
}
public int getRequestedJailCards() {
return requestedJailCards;
}
public List<PropertyField> getRequestedProperties() {
return requestedProperties;
}
public Player getSender() {
return sender;
}
public Boolean getStatus() {
return status;
}
/**
* Initiates the trade and validates its terms.
*
* @return true if the trade is valid and can proceed, false otherwise
*/
public boolean initiateTrade() {
if (!validateTrade()) {
System.out.println("Trade offer is invalid.");
return false;
}
// Notify the receiver about the trade offer (this would be an actual message in a real implementation)
System.out.println("Trade offer initiated by " + sender.getName() + " to " + receiver.getName());
System.out.println("Trade initiated by " + sender.getName() + " to " + receiver.getName());
return true;
}
/**
* Accepts the trade offer and completes the trade between two players.
*
* @param sender the Player who initiated the trade
* @param receiver the Player who accepted the trade
* @param offeredAmount the amount of money to transfer from the sender to the receiver
* @param offeredProperties the list of properties to transfer from the sender to the receiver
* @param offeredJailCards the number of jail cards to transfer from the sender to the receiver
* @param requestedAmount the amount of money to transfer from the receiver to the sender
* @param requestedProperties the list of properties to transfer from the receiver to the sender
* @param requestedJailCards the number of jail cards to transfer from the receiver to the sender
* Completes the trade by transferring money, properties, and jail cards.
*/
public void acceptTrade(Player sender, Player receiver, int offeredAmount, List<PropertyField> offeredProperties,
int offeredJailCards, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
public void acceptTrade() {
// Transfer money
sender.earnMoney(-offeredAmount); // Deduct money from the sender
receiver.earnMoney(offeredAmount); // Add money to the receiver
sender.earnMoney(-offeredAmount);
receiver.earnMoney(offeredAmount);
receiver.earnMoney(-requestedAmount); // Deduct money from the receiver
sender.earnMoney(requestedAmount); // Add money to the sender
receiver.earnMoney(-requestedAmount);
sender.earnMoney(requestedAmount);
// Transfer ownership of the properties from sender to receiver
// Transfer properties
if (offeredProperties != null) {
for (PropertyField property : offeredProperties) {
transferProperty(sender, receiver, property);
}
}
// Transfer ownership of the properties from receiver to sender
if (requestedProperties != null) {
for (PropertyField property : requestedProperties) {
transferProperty(receiver, sender, property);
@@ -76,73 +122,57 @@ public class TradeHandler {
transferJailCards(sender, receiver, offeredJailCards);
transferJailCards(receiver, sender, requestedJailCards);
System.out.println("Trade accepted. " + sender.getName() + " and " + receiver.getName() + " completed the trade.");
System.out.println("Trade completed between " + sender.getName() + " and " + receiver.getName());
}
/**
* Rejects the trade offer.
*
* @param receiver the Player who is rejecting the trade
* Rejects the trade.
*/
public void rejectTrade(Player receiver) {
System.out.println("Trade rejected by " + receiver.getName());
public void rejectTrade() {
System.out.println(receiver.getName() + " rejected the trade.");
}
/**
* Validates a trade offer by checking if the sender and receiver own the properties involved,
* have sufficient funds for the money involved in the trade, and have enough jail cards.
* Validates the trade offer by checking ownership, balances, and jail cards.
*
* @param sender the Player initiating the trade
* @param offeredAmount the amount of money the sender is offering
* @param offeredProperties the list of properties the sender is offering
* @param offeredJailCards the number of jail cards the sender is offering
* @param receiver the Player receiving the trade offer
* @param requestedAmount the amount of money the sender is requesting
* @param requestedProperties the list of properties the sender is requesting from the receiver
* @param requestedJailCards the number of jail cards the sender is requesting from the receiver
* @return true if the trade offer is valid, false otherwise
* @return true if the trade is valid, false otherwise
*/
private boolean validateTrade(Player sender, int offeredAmount, List<PropertyField> offeredProperties, int offeredJailCards,
Player receiver, int requestedAmount, List<PropertyField> requestedProperties, int requestedJailCards) {
// Check if sender has enough money to offer
private boolean validateTrade() {
// Validate sender's ability to offer money
if (sender.getAccountBalance() < offeredAmount) {
System.out.println("Sender does not have enough balance to make this offer.");
System.out.println("Sender does not have enough money to offer.");
return false;
}
// Check if receiver has enough money to offer
// Validate receiver's ability to fulfill the requested amount
if (receiver.getAccountBalance() < requestedAmount) {
System.out.println("Receiver does not have enough balance to fulfill requested amount.");
System.out.println("Receiver does not have enough money to fulfill the request.");
return false;
}
// Check if sender owns all the offered properties
// Validate property ownership
if (offeredProperties != null) {
for (PropertyField property : offeredProperties) {
if (!sender.getProperties().contains(property)) {
System.out.println("Sender does not own the property " + property.getName() + " being offered.");
System.out.println("Sender does not own property: " + property.getName());
return false;
}
}
}
// Check if receiver owns all the requested properties
if (requestedProperties != null) {
for (PropertyField property : requestedProperties) {
if (!receiver.getProperties().contains(property)) {
System.out.println("Receiver does not own the property " + property.getName() + " requested.");
System.out.println("Receiver does not own property: " + property.getName());
return false;
}
}
}
// Check if sender has enough jail cards to offer
// Validate jail cards
if (sender.getNumJailCard() < offeredJailCards) {
System.out.println("Sender does not have enough jail cards to offer.");
return false;
}
// Check if receiver has enough jail cards to fulfill the request
if (receiver.getNumJailCard() < requestedJailCards) {
System.out.println("Receiver does not have enough jail cards to fulfill the request.");
return false;
@@ -152,17 +182,16 @@ public class TradeHandler {
}
/**
* Transfers a property from one player to another.
* Transfers a property between players.
*
* @param from the Player transferring the property
* @param to the Player receiving the property
* @param from the Player transferring the property
* @param to the Player receiving the property
* @param property the PropertyField being transferred
*/
private void transferProperty(Player from, Player to, PropertyField property) {
from.sellProperty(property);
to.buyProperty(property);
property.setOwner(to); // Update the property's owner
property.setOwner(to);
System.out.println("Property " + property.getName() + " transferred from " + from.getName() + " to " + to.getName());
}
@@ -178,6 +207,6 @@ public class TradeHandler {
from.removeJailCard();
to.addJailCard();
}
System.out.println("Transferred " + numCards + " jail card(s) from " + from.getName() + " to " + to.getName());
System.out.println(numCards + " jail card(s) transferred from " + from.getName() + " to " + to.getName());
}
}

View File

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

View File

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

View File

@@ -22,49 +22,49 @@ public class BoardManager {
* Creates a Monopoly GameBoard
* @return the List of Fields in correct Order
*/
private static List<Field> createBoard() {
public static List<Field> createBoard() {
ArrayList<Field> fields = new ArrayList<>();
fields.add(new GoField());
fields.add(new BuildingProperty("Gym", 1, 600, 20));
fields.add(new BuildingProperty("Gym", 1, 600, 20, 500, FieldColor.BROWN));
fields.add(new EventField("Hausfeier", 2));
fields.add(new BuildingProperty("Sportplatz", 3, 600, 40));
fields.add(new BuildingProperty("Sportplatz", 3, 600, 40, 500, FieldColor.BROWN));
fields.add(new FineField("Diszi", 4, 2000));
fields.add(new GateField("Südtor", 5));
fields.add(new BuildingProperty("Studium+", 6, 1000, 60));
fields.add(new BuildingProperty("Studium+", 6, 1000, 60, 500, FieldColor.BLUE_LIGHT));
fields.add(new EventField("Üvas", 7));
fields.add(new BuildingProperty("PhysikHörsaal", 8, 1000, 60));
fields.add(new BuildingProperty("Audimax", 9, 1200, 80));
fields.add(new BuildingProperty("PhysikHörsaal", 8, 1000, 60, 500, FieldColor.BLUE_LIGHT));
fields.add(new BuildingProperty("Audimax", 9, 1200, 80, 500, FieldColor.BLUE_LIGHT));
fields.add(new GulagField());
fields.add(new BuildingProperty("99er", 11, 1400, 100));
fields.add(new BuildingProperty("99er", 11, 1400, 100, 1000, FieldColor.PINK));
fields.add(new FoodField("Brandl", 12));
fields.add(new BuildingProperty("12er", 13, 1400, 100));
fields.add(new BuildingProperty("23er", 14, 1600, 120));
fields.add(new BuildingProperty("12er", 13, 1400, 100, 1000, FieldColor.PINK));
fields.add(new BuildingProperty("23er", 14, 1600, 120, 1000, FieldColor.PINK));
fields.add(new GateField("HauptWache", 15));
fields.add(new BuildingProperty("Schwimmhalle", 16, 1800, 140));
fields.add(new BuildingProperty("CISM-Bahn", 17, 1800, 140));
fields.add(new BuildingProperty("Schwimmhalle", 16, 1800, 140, 1000, FieldColor.ORANGE));
fields.add(new BuildingProperty("CISM-Bahn", 17, 1800, 140, 1000, FieldColor.ORANGE));
fields.add(new EventField("Marine-Welcome-Party", 18));
fields.add(new BuildingProperty("Kletterturm", 19, 2000, 160));
fields.add(new BuildingProperty("Kletterturm", 19, 2000, 160, 1000, FieldColor.ORANGE));
fields.add(new TestStreckeField());
fields.add(new BuildingProperty("StudFBer C", 21, 2200, 180));
fields.add(new BuildingProperty("StudFBer C", 21, 2200, 180, 1500, FieldColor.RED));
fields.add(new EventField("Üvas", 22));
fields.add(new BuildingProperty("StudFBer B", 23, 2200, 180));
fields.add(new BuildingProperty("StudFBer A", 24, 2400, 200));
fields.add(new BuildingProperty("StudFBer B", 23, 2200, 180, 1500, FieldColor.RED));
fields.add(new BuildingProperty("StudFBer A", 24, 2400, 200, 1500, FieldColor.RED));
fields.add(new GateField("Nordtor", 25));
fields.add(new BuildingProperty("Cascada", 26, 2600, 220));
fields.add(new BuildingProperty("Fakultätsgebäude", 27, 2600, 220));
fields.add(new BuildingProperty("Cascada", 26, 2600, 220, 1500, FieldColor.YELLOW));
fields.add(new BuildingProperty("Fakultätsgebäude", 27, 2600, 220, 1500, FieldColor.YELLOW));
fields.add(new FoodField("Truppenküche", 28));
fields.add(new BuildingProperty("Prüfungsamt", 29, 2800, 240));
fields.add(new BuildingProperty("Prüfungsamt", 29, 2800, 240, 1500, FieldColor.YELLOW));
fields.add(new WacheField());
fields.add(new BuildingProperty("Feuerwehr", 31, 3000, 260));
fields.add(new BuildingProperty("SanZ", 32, 300, 260));
fields.add(new BuildingProperty("Feuerwehr", 31, 3000, 260, 2000, FieldColor.GREEN));
fields.add(new BuildingProperty("SanZ", 32, 300, 260, 2000, FieldColor.GREEN));
fields.add(new EventField("Maibock", 33));
fields.add(new BuildingProperty("Rechenzentrum", 34, 3200, 280));
fields.add(new BuildingProperty("Rechenzentrum", 34, 3200, 280, 2000, FieldColor.GREEN));
fields.add(new GateField("Osttor", 35));
fields.add(new EventField("Üvas", 36));
fields.add(new BuildingProperty("2er", 37, 3500, 350));
fields.add(new BuildingProperty("2er", 37, 3500, 350, 2000, FieldColor.BLUE_DARK));
fields.add(new FineField("EZM", 38, 1000));
fields.add(new BuildingProperty("20er", 39, 4000, 500));
fields.add(new BuildingProperty("20er", 39, 4000, 500, 2000, FieldColor.BLUE_DARK));
return fields;
}
@@ -88,4 +88,8 @@ public class BoardManager {
if (board.contains(field)) return field.getId();
else throw new NoSuchElementException();
}
public List<Field> getBoard() {
return board;
}
}

View File

@@ -1,30 +1,42 @@
package pp.monopoly.model.fields;
import java.util.ArrayList;
import java.util.List;
import pp.monopoly.game.server.Player;
public class BuildingProperty extends PropertyField {
private int houses;
private boolean hotel = false;
private final int housePrice;
private final FieldColor color;
private final int rentFactor1 = 5;
private final int rentFactor2 = 15;
private final int rentFactor3 = 40;
private final int rentFactor4 = 55;
private final int rentFactorHotel = 70;
BuildingProperty(String name, int id, int price, int rent) {
BuildingProperty(String name, int id, int price, int rent, int housePrice, FieldColor color) {
super(name, id, price, rent);
this.housePrice = housePrice;
this.color = color;
}
@Override
public int calcRent() {
if (hotel) {
return (int) Math.round(rent*70/10)*10;
return (int) Math.round(rent*rentFactorHotel/10)*10;
}
switch (houses) {
case 1:
return (int) Math.round(rent*5/10)*10;
return (int) Math.round(rent*rentFactor1/10)*10;
case 2:
return (int) Math.round(rent*15/10)*10;
return (int) Math.round(rent*rentFactor2/10)*10;
case 3:
return (int) Math.round(rent*40/10)*10;
return (int) Math.round(rent*rentFactor3/10)*10;
case 4:
return (int) Math.round(rent*55/10)*10;
return (int) Math.round(rent*rentFactor4/10)*10;
default:
return rent;
@@ -67,4 +79,31 @@ public class BuildingProperty extends PropertyField {
public void accept(Player player) {
player.visit(this);
}
public List<Integer> getAllRent() {
List<Integer> list = new ArrayList<>();
list.add(rent);
list.add((int) Math.round(rent*rentFactor1/10)*10);
list.add((int) Math.round(rent*rentFactor2/10)*10);
list.add((int) Math.round(rent*rentFactor3/10)*10);
list.add((int) Math.round(rent*rentFactor4/10)*10);
list.add((int) Math.round(rent*rentFactorHotel/10)*10);
return list;
}
public FieldColor getColor() {
return color;
}
public int getHousePrice() {
return housePrice;
}
public int getHouses() {
return houses;
}
public int getHotel() {
return hotel ? 1:0;
}
}

View File

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

View File

@@ -0,0 +1,37 @@
package pp.monopoly.model.fields;
import com.jme3.math.ColorRGBA;
/**
* Enum representing eight distinct colors for properties in the game.
*/
public enum FieldColor {
BROWN(new ColorRGBA(148 / 255f, 86 / 255f, 57 / 255f, 1)),
GREEN(new ColorRGBA(30 / 255f, 179 / 255f, 90 / 255f, 1)),
YELLOW(new ColorRGBA(252 / 255f, 241 / 255f, 1 / 255f, 1)),
BLUE_LIGHT(new ColorRGBA(170 / 255f, 223 / 255f, 246 / 255f, 1)),
PINK(new ColorRGBA(214 / 255f, 60 / 255f, 153 / 255f, 1)),
ORANGE(new ColorRGBA(244 / 255f, 147 / 255f, 32 / 255f, 1)),
RED(new ColorRGBA(232 / 255f, 27 / 255f, 30 / 255f, 1)),
BLUE_DARK(new ColorRGBA(2 / 255f, 112 / 255f, 191 / 255f, 1));
private final ColorRGBA color;
/**
* Constructs a FieldColor with the specified ColorRGBA value.
*
* @param color the ColorRGBA value associated with the field color
*/
FieldColor(ColorRGBA color) {
this.color = color;
}
/**
* Gets the ColorRGBA value of the field color.
*
* @return the ColorRGBA value
*/
public ColorRGBA getColor() {
return color;
}
}

View File

@@ -15,4 +15,8 @@ public class GulagField extends Field{
player.visit(this);
}
public int getBailCost() {
return bailCost;
}
}

View File

@@ -19,6 +19,8 @@ public class TestStreckeField extends Field{
}
public int collectMoney() {
return money = 0;
int tmp = money;
money = 0;
return tmp;
}
}