merge dev into test #33
@@ -1,5 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="MdgaApp" type="Application" factoryName="Application" singleton="false" nameIsGenerated="true">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="temurin-20" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
|
||||
<option name="MAIN_CLASS_NAME" value="pp.mdga.client.MdgaApp" />
|
||||
<module name="Projekte.mdga.client.main" />
|
||||
<option name="VM_PARAMETERS" value="-Djava.util.logging.config.file=logging.properties -ea" />
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package pp.mdga.client;
|
||||
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
|
||||
/**
|
||||
* An abstract control class that serves as a base for initializing spatial objects
|
||||
* in jMonkeyEngine. This class overrides the controlUpdate and controlRender methods
|
||||
* from the AbstractControl class, providing default empty implementations,
|
||||
* and adds the ability to initialize spatial objects when they are set.
|
||||
*/
|
||||
public abstract class InitControl extends AbstractControl {
|
||||
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the spatial object to be controlled. This method also initializes the spatial
|
||||
* if it is being set for the first time.
|
||||
*
|
||||
* @param spatial The spatial object to control.
|
||||
*/
|
||||
@Override
|
||||
public void setSpatial(Spatial spatial) {
|
||||
if (this.spatial == null && spatial != null) {
|
||||
super.setSpatial(spatial);
|
||||
initSpatial();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the spatial object. This method can be overridden by subclasses
|
||||
* to define custom initialization logic for the spatial.
|
||||
* This method is called automatically when the spatial is set for the first time.
|
||||
*/
|
||||
protected void initSpatial() {
|
||||
// Default empty implementation. Override to add initialization logic.
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,13 @@
|
||||
import pp.mdga.client.board.OutlineControl;
|
||||
import pp.mdga.client.board.PieceControl;
|
||||
import pp.mdga.client.gui.CardControl;
|
||||
import pp.mdga.client.gui.DiceControl;
|
||||
import pp.mdga.client.view.GameView;
|
||||
import pp.mdga.game.BonusCard;
|
||||
import pp.mdga.game.Color;
|
||||
import pp.mdga.game.Piece;
|
||||
import pp.mdga.notification.FinishNotification;
|
||||
import pp.mdga.notification.MovePieceNotification;
|
||||
import pp.mdga.notification.SelectableCardsNotification;
|
||||
|
||||
import java.util.List;
|
||||
@@ -92,10 +94,14 @@ public void onAction(String name, boolean isPressed, float tpf) {
|
||||
}
|
||||
if(name.equals("Click") && isPressed) {
|
||||
if (app.getView() instanceof GameView gameView) {
|
||||
DiceControl diceSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), DiceControl.class);
|
||||
CardControl cardLayerSelect = checkHover(gameView.getGuiHandler().getCardLayerCamera(), gameView.getGuiHandler().getCardLayerRootNode(), CardControl.class);
|
||||
OutlineControl boardSelect = checkHover(app.getCamera(), app.getRootNode(), OutlineControl.class);
|
||||
|
||||
if(cardLayerSelect != null) {
|
||||
if(diceSelect != null) {
|
||||
app.getModelSynchronize().rolledDice();
|
||||
}
|
||||
else if(cardLayerSelect != null) {
|
||||
//cardSelect
|
||||
if(cardLayerSelect.isSelectable()) gameView.getGuiHandler().selectCard(cardLayerSelect);
|
||||
}
|
||||
@@ -117,7 +123,11 @@ else if(boardSelect != null) {
|
||||
}
|
||||
if(name.equals("Test") &&isPressed){
|
||||
if(app.getView() instanceof GameView gameView){
|
||||
app.getNotificationSynchronizer().addTestNotification(new FinishNotification(Color.NAVY));
|
||||
// gameView.getGuiHandler().rollRankingResult(Color.AIRFORCE, 1);
|
||||
// gameView.getGuiHandler().rollRankingResult(Color.ARMY, 2);
|
||||
// gameView.getGuiHandler().rollRankingResult(Color.NAVY, 3);
|
||||
// gameView.getGuiHandler().rollRankingResult(Color.CYBER, 4);
|
||||
gameView.getGuiHandler().showDice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package pp.mdga.client;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.system.JmeContext;
|
||||
import com.jme3.system.AppSettings;
|
||||
import com.simsilica.lemur.GuiGlobals;
|
||||
import pp.mdga.client.acoustic.AcousticHandler;
|
||||
import pp.mdga.client.animation.AnimationHandler;
|
||||
import com.jme3.system.AppSettings;
|
||||
import pp.mdga.client.dialog.JoinDialog;
|
||||
import pp.mdga.client.view.*;
|
||||
import pp.mdga.message.server.ServerInterpreter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -23,9 +20,6 @@ public class MdgaApp extends SimpleApplication {
|
||||
|
||||
private static Preferences prefs = Preferences.userNodeForPackage(JoinDialog.class);
|
||||
|
||||
/** Handles animations in the application. */
|
||||
private AnimationHandler animationHandler;
|
||||
|
||||
/** Handles acoustic effects and state-based sounds. */
|
||||
private AcousticHandler acousticHandler;
|
||||
|
||||
@@ -88,6 +82,7 @@ public static void main(String[] args) {
|
||||
MdgaApp app = new MdgaApp();
|
||||
app.setSettings(settings);
|
||||
app.setShowSettings(false);
|
||||
app.setPauseOnLostFocus(false);
|
||||
app.start();
|
||||
}
|
||||
|
||||
@@ -102,7 +97,6 @@ public void simpleInitApp() {
|
||||
|
||||
flyCam.setEnabled(false);
|
||||
|
||||
animationHandler = new AnimationHandler(this);
|
||||
acousticHandler = new AcousticHandler(this);
|
||||
notificationSynchronizer = new NotificationSynchronizer(this);
|
||||
inputSynchronizer = new InputSynchronizer(this);
|
||||
@@ -163,14 +157,6 @@ public void enter(MdgaState state) {
|
||||
view.enter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animation handler.
|
||||
*
|
||||
* @return the {@link AnimationHandler} instance
|
||||
*/
|
||||
public AnimationHandler getAnimationHandler() {
|
||||
return animationHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the acoustic handler.
|
||||
|
||||
@@ -107,8 +107,8 @@ public void selectTsk(Color color) {
|
||||
app.getGameLogic().selectTsk(color);
|
||||
}
|
||||
|
||||
public void unselectTsk() {
|
||||
app.getGameLogic().selectTsk(Color.NONE);
|
||||
public void unselectTsk(Color color) {
|
||||
app.getGameLogic().deselectTSK(color);
|
||||
}
|
||||
|
||||
public void rolledDice() {
|
||||
|
||||
@@ -60,15 +60,15 @@ private void handleLobby(Notification notification) {
|
||||
|
||||
if (notification instanceof TskSelectNotification n) {
|
||||
lobbyView.setTaken(n.getColor(), true, n.isSelf(), n.getName());
|
||||
lobbyView.setTaken(n.getColor(), true, false, n.getName());
|
||||
} else if (notification instanceof StartDialogNotification) {
|
||||
app.enter(MdgaState.MAIN);
|
||||
} else if (notification instanceof TskUnselectNotification n) {
|
||||
lobbyView.setTaken(n.getColor(), false, false, null);
|
||||
} else if(notification instanceof LobbyReadyNotification lobbyReadyNotification) {
|
||||
lobbyView.setReady(lobbyReadyNotification.getColor(), lobbyReadyNotification.isReady());
|
||||
} else if (notification instanceof GameNotification) {
|
||||
} else if (notification instanceof GameNotification n) {
|
||||
app.enter(MdgaState.GAME);
|
||||
((GameView) app.getView()).setOwnColor(n.getOwnColor());
|
||||
} else {
|
||||
throw new RuntimeException("notification not expected: " + notification.toString());
|
||||
}
|
||||
@@ -84,6 +84,7 @@ private void handleGame(Notification notification) {
|
||||
guiHandler.addCard(n.getBonusCard());
|
||||
} else if (notification instanceof ActivePlayerNotification n) {
|
||||
gameView.getGuiHandler().setActivePlayer(n.getColor());
|
||||
boardHandler.showDice(n.getColor());
|
||||
} else if (notification instanceof CeremonyNotification ceremonyNotification) {
|
||||
app.enter(MdgaState.CEREMONY);
|
||||
CeremonyView ceremonyView = (CeremonyView) app.getView();
|
||||
@@ -116,22 +117,22 @@ private void handleGame(Notification notification) {
|
||||
} else if (notification instanceof DrawCardNotification n) {
|
||||
guiHandler.drawCard(n.getColor());
|
||||
} else if (notification instanceof HomeMoveNotification home) {
|
||||
boardHandler.moveHomePiece(home.getPieceId(), home.getHomeIndex());
|
||||
boardHandler.movePieceHomeAnim(home.getPieceId(), home.getHomeIndex());
|
||||
guiHandler.hideText();
|
||||
} else if (notification instanceof InterruptNotification) {
|
||||
app.enter(MdgaState.LOBBY);
|
||||
} else if (notification instanceof MovePieceNotification n) {
|
||||
if(n.isMoveStart()) {
|
||||
//StartMove
|
||||
boardHandler.movePieceStart(n.getPiece(), n.getMoveIndex());
|
||||
boardHandler.movePieceStartAnim(n.getPiece(), n.getMoveIndex());
|
||||
}
|
||||
else {
|
||||
//InfieldMove
|
||||
boardHandler.movePiece(n.getPiece(), n.getStartIndex(), n.getMoveIndex());
|
||||
boardHandler.movePieceAnim(n.getPiece(), n.getStartIndex(), n.getMoveIndex());
|
||||
}
|
||||
guiHandler.hideText();
|
||||
} else if (notification instanceof ThrowPieceNotification n) {
|
||||
boardHandler.throwPiece(n.getPieceId());
|
||||
boardHandler.throwPieceAnim(n.getPieceId());
|
||||
} else if (notification instanceof NoShieldNotification n) {
|
||||
boardHandler.unshieldPiece(n.getPieceId());
|
||||
} else if (notification instanceof PlayCardNotification n) {
|
||||
@@ -147,10 +148,12 @@ private void handleGame(Notification notification) {
|
||||
} else if (notification instanceof ResumeNotification) {
|
||||
//TODO
|
||||
} else if (notification instanceof RollDiceNotification n) {
|
||||
gameView.getGuiHandler().hideText();
|
||||
if(n.getColor() == gameView.getOwnColor()){
|
||||
guiHandler.rollDice(n.getEyes(), n.isTurbo() ? n.getMultiplier() : -1);
|
||||
}
|
||||
else {
|
||||
boardHandler.hideDice();
|
||||
if (n.isTurbo()) guiHandler.showRolledDiceMult(n.getEyes(), n.getMultiplier(), n.getColor());
|
||||
else guiHandler.showRolledDice(n.getEyes(), n.getColor());
|
||||
}
|
||||
@@ -163,7 +166,7 @@ private void handleGame(Notification notification) {
|
||||
} else if (notification instanceof StartDialogNotification) {
|
||||
app.enter(MdgaState.MAIN);
|
||||
} else if (notification instanceof SwapPieceNotification n) {
|
||||
boardHandler.swapPieces(n.getFirstPiece(), n.getSecondPiece());
|
||||
// boardHandler.swapPieces(n.getFirstPiece(), n.getSecondPiece());
|
||||
guiHandler.swap();
|
||||
} else if (notification instanceof WaitMoveNotification) {
|
||||
//TODO ???
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
abstract class Animation {
|
||||
|
||||
abstract void play();
|
||||
|
||||
abstract void stop();
|
||||
|
||||
abstract boolean isOver();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
import pp.mdga.client.MdgaApp;
|
||||
|
||||
public class AnimationHandler {
|
||||
private MdgaApp app;
|
||||
|
||||
private Animation animation = null;
|
||||
|
||||
public AnimationHandler(MdgaApp app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public void playAnimation(MdgaAnimation type) {
|
||||
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (null == animation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (animation.isOver()) {
|
||||
animation = null;
|
||||
|
||||
//trigger next state in model
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
class EmptyAnimation extends Animation {
|
||||
@Override
|
||||
void play() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
void stop() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isOver() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
public enum MdgaAnimation {
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import pp.mdga.client.InitControl;
|
||||
|
||||
/**
|
||||
* A control that smoothly moves a spatial from an initial position to an end position
|
||||
* using a quadratic interpolation, with the option to perform an action after the movement is complete.
|
||||
* The movement path includes an intermediate "middle" position at a specified height.
|
||||
*
|
||||
* <p>Movement speed can be adjusted by modifying the MOVE_SPEED constant. The movement easing follows
|
||||
* an ease-in-out curve to create a smooth start and stop effect.
|
||||
* </p>
|
||||
*/
|
||||
public class MoveControl extends InitControl {
|
||||
|
||||
private boolean moving;
|
||||
private final Vector3f initPos;
|
||||
private final Vector3f endPos;
|
||||
private final Vector3f middlePos;
|
||||
private final static float HEIGHT = 2;
|
||||
private final static float MOVE_SPEED = 1f;
|
||||
private float progress = 0;
|
||||
private final Runnable actionAfter;
|
||||
|
||||
/**
|
||||
* Creates a new MoveControl with specified initial and end positions, and an action to run after the movement.
|
||||
* The movement follows a path with a midpoint at a fixed height.
|
||||
*
|
||||
* @param initPos The starting position of the spatial.
|
||||
* @param endPos The target position of the spatial.
|
||||
* @param actionAfter A Runnable that will be executed after the movement finishes.
|
||||
*/
|
||||
public MoveControl(Vector3f initPos, Vector3f endPos, Runnable actionAfter){
|
||||
moving = false;
|
||||
this.initPos = initPos;
|
||||
this.endPos = endPos;
|
||||
middlePos = new Vector3f(
|
||||
(initPos.x + endPos.x) / 2,
|
||||
(initPos.y + endPos.y) / 2,
|
||||
HEIGHT
|
||||
);
|
||||
this.actionAfter = actionAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the movement by resetting the progress and setting the moving flag to true.
|
||||
* This is called automatically when the spatial is set.
|
||||
*/
|
||||
@Override
|
||||
protected void initSpatial() {
|
||||
moving = true;
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the movement of the spatial by interpolating its position along the defined path.
|
||||
* The movement is smoothed using an easing function.
|
||||
* Once the movement reaches the target, the {@link #end()} method is called to finish the movement.
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if(!moving) return;
|
||||
progress += tpf * MOVE_SPEED;
|
||||
if(progress > 1) progress = 1;
|
||||
spatial.setLocalTranslation(quadInt(initPos,middlePos,endPos, easeInOut(progress)));
|
||||
if(progress == 1) end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the movement by stopping the interpolation, running the action after the movement,
|
||||
* and removing this control from the spatial.
|
||||
*/
|
||||
private void end(){
|
||||
moving = false;
|
||||
actionAfter.run();
|
||||
spatial.removeControl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs quadratic interpolation between three points.
|
||||
*
|
||||
* @param p1 The initial point.
|
||||
* @param p2 The middle point.
|
||||
* @param p3 The final point.
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The interpolated point.
|
||||
*/
|
||||
private Vector3f quadInt(Vector3f p1, Vector3f p2, Vector3f p3, float t) {
|
||||
// Quadratic interpolation: (1-t)^2 * p1 + 2 * (1-t) * t * p2 + t^2 * p3
|
||||
float oneMinusT = 1 - t;
|
||||
return p1.mult(oneMinusT * oneMinusT)
|
||||
.add(p2.mult(2 * oneMinusT * t))
|
||||
.add(p3.mult(t * t));
|
||||
}
|
||||
|
||||
/**
|
||||
* A smooth ease-in-out function for interpolation.
|
||||
* It accelerates and decelerates the interpolation for a smoother effect.
|
||||
*
|
||||
* @param x The interpolation parameter (0 <= x <= 1).
|
||||
* @return The adjusted interpolation value.
|
||||
*/
|
||||
private float easeInOut(float x){
|
||||
return x < 0.5 ? 4 * x * x * x : (float) (1 - Math.pow(-2 * x + 2, 3) / 2);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,23 @@
|
||||
package pp.mdga.client.gui;
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.mdga.client.InitControl;
|
||||
import pp.mdga.game.BonusCard;
|
||||
|
||||
public class SymbolControl extends AbstractControl {
|
||||
/**
|
||||
* A control that manages the animation of symbols representing different bonus card states.
|
||||
* The symbol can animate with zoom, rotation, and translation effects based on the state of the bonus card.
|
||||
*
|
||||
* <p>The control supports three main states: SHIELD, SWAP, and TURBO. Each state has its own specific animation logic:
|
||||
* <ul>
|
||||
* <li>SHIELD: Zooms in and out, with a scaling effect.</li>
|
||||
* <li>SWAP: Rotates the symbol 360 degrees.</li>
|
||||
* <li>TURBO: Moves the symbol along the Y-axis with a zoom effect.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public class SymbolControl extends InitControl {
|
||||
private boolean zoomingIn = false;
|
||||
private boolean zoomingOut = false;
|
||||
private float zoomSpeed = 1f;
|
||||
@@ -18,7 +28,12 @@ public class SymbolControl extends AbstractControl {
|
||||
private Quaternion initialRotation = null;
|
||||
private float y = 5;
|
||||
|
||||
|
||||
/**
|
||||
* Updates the symbol animation based on the current bonus card state.
|
||||
* The method calls the corresponding update method for each state (SHIELD, SWAP, TURBO).
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (state == null) return;
|
||||
@@ -30,11 +45,12 @@ protected void controlUpdate(float tpf) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the symbol when the state is SHIELD. The symbol zooms in and then zooms out.
|
||||
* When the zooming out finishes, the symbol is removed from the parent spatial.
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
private void shieldUpdate(float tpf) {
|
||||
if (zoomingIn) {
|
||||
progress += tpf * zoomSpeed;
|
||||
@@ -57,6 +73,12 @@ private void shieldUpdate(float tpf) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the symbol when the state is SWAP. The symbol rotates 360 degrees.
|
||||
* After the rotation finishes, the symbol is removed from the parent spatial.
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
private void swapUpdate(float tpf) {
|
||||
if (initialRotation == null) {
|
||||
initialRotation = spatial.getLocalRotation().clone();
|
||||
@@ -80,6 +102,12 @@ private void swapUpdate(float tpf) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the symbol when the state is TURBO. The symbol moves along the Y-axis with a zoom effect.
|
||||
* After the movement finishes, the symbol is removed from the parent spatial.
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
private void turboUpdate(float tpf) {
|
||||
if (zoomingIn) {
|
||||
progress += tpf * zoomSpeed;
|
||||
@@ -103,6 +131,10 @@ private void turboUpdate(float tpf) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the SHIELD animation by zooming the symbol in and out.
|
||||
* The symbol will first zoom in and then zoom out, and will be removed from the parent spatial once done.
|
||||
*/
|
||||
public void shield() {
|
||||
if (state != null) throw new RuntimeException("another state is avtive");
|
||||
state = BonusCard.SHIELD;
|
||||
@@ -112,6 +144,10 @@ public void shield() {
|
||||
spatial.setLocalScale(1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the SWAP animation by rotating the symbol 360 degrees.
|
||||
* The symbol will rotate once and then be removed from the parent spatial.
|
||||
*/
|
||||
public void swap() {
|
||||
if (state != null) throw new RuntimeException("another state is avtive");
|
||||
spatial.setLocalScale(3);
|
||||
@@ -119,6 +155,10 @@ public void swap() {
|
||||
progress = -0.2f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the TURBO animation by moving the symbol along the Y-axis.
|
||||
* The symbol will move upwards and then return to its initial position.
|
||||
*/
|
||||
public void turbo() {
|
||||
if (state != null) throw new RuntimeException("another state is avtive");
|
||||
spatial.setLocalScale(2);
|
||||
@@ -128,19 +168,45 @@ public void turbo() {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs linear interpolation between two values.
|
||||
*
|
||||
* @param start The starting value.
|
||||
* @param end The target value.
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
private static float lerp(float start, float end, float t) {
|
||||
return (1 - t) * start + t * end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ease-out function for smoothing the interpolation.
|
||||
*
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The eased value.
|
||||
*/
|
||||
private static float easeOut(float t) {
|
||||
return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ease-in-out function for smoothing the interpolation.
|
||||
*
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The eased value.
|
||||
*/
|
||||
private float easeInOut(float t) {
|
||||
if (t > 1) t = 1;
|
||||
return (float) -(Math.cos(Math.PI * t) - 1) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ease-in function for smoothing the interpolation.
|
||||
*
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The eased value.
|
||||
*/
|
||||
private float easeIn(float t) {
|
||||
return t * t * t * t;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package pp.mdga.client.animation;
|
||||
|
||||
import pp.mdga.client.InitControl;
|
||||
|
||||
/**
|
||||
* A control that applies a zoom effect to a spatial, smoothly scaling it in and out.
|
||||
* The zoom effect can be customized with speed and scaling factor.
|
||||
*
|
||||
* <p>The control supports zooming in and out with ease-in and ease-out transitions.
|
||||
* It starts by zooming in, and once complete, it zooms out, eventually removing the spatial from its parent when the animation ends.</p>
|
||||
*/
|
||||
public class ZoomControl extends InitControl {
|
||||
private boolean zoomingIn = false;
|
||||
private boolean zoomingOut = false;
|
||||
private float progress = 0;
|
||||
private float zoomSpeed = 1f;
|
||||
private float zoomFactor = 1f;
|
||||
|
||||
/**
|
||||
* Constructs a new ZoomControl with the default zoom speed.
|
||||
*/
|
||||
public ZoomControl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ZoomControl with a specified zoom speed.
|
||||
*
|
||||
* @param speed The speed at which the zoom effect occurs.
|
||||
*/
|
||||
public ZoomControl(float speed) {
|
||||
zoomSpeed = speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the spatial for the zoom effect. This method is called when the control is added to the spatial.
|
||||
* It sets the zooming state to zooming in.
|
||||
*/
|
||||
@Override
|
||||
protected void initSpatial() {
|
||||
zoomingIn = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the zoom effect over time, either zooming in or zooming out.
|
||||
*
|
||||
* @param tpf Time per frame, the time elapsed since the last frame.
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (zoomingIn) {
|
||||
progress += tpf * zoomSpeed;
|
||||
if (progress > 1) progress = 1;
|
||||
spatial.setLocalScale(lerp(0, zoomFactor, easeOut(progress)));
|
||||
if (progress >= 1) {
|
||||
zoomingIn = false;
|
||||
zoomingOut = true;
|
||||
progress = 0;
|
||||
}
|
||||
} else if (zoomingOut) {
|
||||
progress += tpf * zoomSpeed;
|
||||
spatial.setLocalScale(lerp(zoomFactor, 0, easeIn(progress)));
|
||||
if (progress > 1) {
|
||||
zoomingOut = false;
|
||||
end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the zoom animation by removing the spatial from its parent and the control from the spatial.
|
||||
*/
|
||||
private void end() {
|
||||
spatial.removeFromParent();
|
||||
spatial.removeControl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs linear interpolation between two values.
|
||||
*
|
||||
* @param start The starting value.
|
||||
* @param end The target value.
|
||||
* @param t The interpolation parameter (0 <= t <= 1).
|
||||
* @return The interpolated value.
|
||||
*/
|
||||
private static float lerp(float start, float end, float t) {
|
||||
return (1 - t) * start + t * end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ease-out function for smoothing the zoom-in transition.
|
||||
*
|
||||
* @param x The interpolation parameter (0 <= x <= 1).
|
||||
* @return The eased value.
|
||||
*/
|
||||
private float easeOut(float x) {
|
||||
return x == 1 ? 1 : (float) (1 - Math.pow(2, -10 * x));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ease-in function for smoothing the zoom-out transition.
|
||||
*
|
||||
* @param x The interpolation parameter (0 <= x <= 1).
|
||||
* @return The eased value.
|
||||
*/
|
||||
private float easeIn(float x) {
|
||||
return x == 0 ? 0 : (float) Math.pow(2, 10 * x - 10);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,4 +2,7 @@
|
||||
|
||||
import pp.mdga.client.Asset;
|
||||
|
||||
/**
|
||||
* Record for holding Asset information
|
||||
*/
|
||||
record AssetOnMap(Asset asset, int x, int y, float rot) {}
|
||||
|
||||
@@ -9,34 +9,45 @@
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.mdga.client.Asset;
|
||||
import pp.mdga.client.MdgaApp;
|
||||
import pp.mdga.client.animation.MoveControl;
|
||||
import pp.mdga.client.gui.DiceControl;
|
||||
import pp.mdga.game.Color;
|
||||
import pp.mdga.game.Piece;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* BoardHandler is responsible for managing the game board in the MDGA client, including handling
|
||||
* the initialization, movement, and management of game pieces and assets.
|
||||
* It works closely with the MdgaApp to create and manipulate 3D models of assets, track player pieces,
|
||||
* and manage movement across the game board.
|
||||
*/
|
||||
public class BoardHandler {
|
||||
// Constants defining the grid size and elevation of the board
|
||||
private static final float GRID_SIZE = 1.72f;
|
||||
private static final float GRID_ELEVATION = 0.0f;
|
||||
private static final String MAP_NAME = "Maps/map.mdga";
|
||||
|
||||
// The main application instance for accessing game assets and logic
|
||||
private final MdgaApp app;
|
||||
|
||||
// Collection of in-game assets and board elements
|
||||
private ArrayList<NodeControl> infield;
|
||||
private Map<UUID, PieceControl> pieces;
|
||||
|
||||
private Map<Color, List<AssetOnMap>> colorAssetsMap;
|
||||
private Map<Color, List<NodeControl>> homeNodesMap;
|
||||
private Map<Color, List<NodeControl>> waitingNodesMap;
|
||||
private Map<Color, List<PieceControl>> waitingPiecesMap;
|
||||
private Map<Color, Map<UUID, NodeControl>> waitingNodes;
|
||||
private Map<UUID, Color> pieceColor;
|
||||
|
||||
private Node rootNodeBoard;
|
||||
private final Node rootNodeBoard;
|
||||
private final Node rootNode;
|
||||
|
||||
private final FilterPostProcessor fpp;
|
||||
|
||||
private boolean isInitialised;
|
||||
|
||||
// Flags and lists for handling piece selection and movement
|
||||
private List<PieceControl> selectableOwnPieces;
|
||||
private List<PieceControl> selectableEnemyPieces;
|
||||
private List<NodeControl> outlineNodes;
|
||||
@@ -44,6 +55,14 @@ public class BoardHandler {
|
||||
private PieceControl selectedEnemyPiece;
|
||||
private DiceControl diceControl;
|
||||
|
||||
/**
|
||||
* Creates a new BoardHandler.
|
||||
*
|
||||
* @param app The main application instance
|
||||
* @param rootNode The root node where the board will be attached
|
||||
* @param fpp The post-processor for effects like shadows or filters
|
||||
* @throws RuntimeException if the app is null
|
||||
*/
|
||||
public BoardHandler(MdgaApp app, Node rootNode, FilterPostProcessor fpp) {
|
||||
if(app == null) throw new RuntimeException("app is null");
|
||||
|
||||
@@ -54,6 +73,9 @@ public BoardHandler(MdgaApp app, Node rootNode, FilterPostProcessor fpp) {
|
||||
isInitialised = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the game board by setting up the pieces and nodes.
|
||||
*/
|
||||
public void init() {
|
||||
isInitialised = true;
|
||||
selectableOwnPieces = new ArrayList<>();
|
||||
@@ -65,17 +87,30 @@ public void init() {
|
||||
rootNode.attachChild(rootNodeBoard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the board handler by detaching all board-related nodes and clearing selected pieces.
|
||||
*/
|
||||
public void shutdown(){
|
||||
clearSelectable();
|
||||
isInitialised = false;
|
||||
rootNode.detachChild(rootNodeBoard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asset to the map of player assets, ensuring that the player does not have too many assets.
|
||||
*
|
||||
* @param col The color of the player
|
||||
* @param assetOnMap The asset to be added
|
||||
* @throws RuntimeException if there are too many assets for the player
|
||||
*/
|
||||
private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) {
|
||||
List<AssetOnMap> inMap = addItemToMapList(colorAssetsMap, col, assetOnMap);
|
||||
if (inMap.size() > 4) throw new RuntimeException("to many assets for " + col);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the map with the assets loaded from the map file and corresponding nodes.
|
||||
*/
|
||||
private void initMap() {
|
||||
pieces = new HashMap<>();
|
||||
colorAssetsMap = new HashMap<>();
|
||||
@@ -86,6 +121,12 @@ private void initMap() {
|
||||
pieceColor = new HashMap<>();
|
||||
diceControl = new DiceControl(app.getAssetManager());
|
||||
diceControl.create(new Vector3f(0,0,0), 0.7f, true);
|
||||
waitingNodes = new HashMap<>();
|
||||
waitingNodes.put(Color.AIRFORCE, new HashMap<>());
|
||||
waitingNodes.put(Color.ARMY, new HashMap<>());
|
||||
waitingNodes.put(Color.NAVY, new HashMap<>());
|
||||
waitingNodes.put(Color.CYBER, new HashMap<>());
|
||||
|
||||
|
||||
List<AssetOnMap> assetOnMaps = MapLoader.loadMap(MAP_NAME);
|
||||
|
||||
@@ -111,6 +152,13 @@ private void initMap() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an asset to its corresponding color.
|
||||
*
|
||||
* @param asset The asset to be converted
|
||||
* @return The color associated with the asset
|
||||
* @throws RuntimeException if the asset is invalid
|
||||
*/
|
||||
private Color assetToColor(Asset asset) {
|
||||
return switch (asset) {
|
||||
case lw -> Color.AIRFORCE;
|
||||
@@ -121,6 +169,14 @@ private Color assetToColor(Asset asset) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 3D model of an asset and adds it to the board.
|
||||
*
|
||||
* @param asset The asset to be displayed
|
||||
* @param pos The position of the asset on the board
|
||||
* @param rot The rotation of the asset
|
||||
* @return The Spatial representation of the asset
|
||||
*/
|
||||
private Spatial createModel(Asset asset, Vector3f pos, float rot) {
|
||||
String modelName = asset.getModelPath();
|
||||
String texName = asset.getDiffPath();
|
||||
@@ -137,10 +193,23 @@ private Spatial createModel(Asset asset, Vector3f pos, float rot) {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts grid coordinates to world space.
|
||||
*
|
||||
* @param x The x-coordinate on the grid
|
||||
* @param y The y-coordinate on the grid
|
||||
* @return The corresponding world position
|
||||
*/
|
||||
private static Vector3f gridToWorld(int x, int y) {
|
||||
return new Vector3f(GRID_SIZE * x, GRID_SIZE * y, GRID_ELEVATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an asset on the map at the given position with the specified rotation.
|
||||
*
|
||||
* @param assetOnMap The asset to be displayed.
|
||||
* @return A spatial representation of the asset at the specified location and rotation.
|
||||
*/
|
||||
private Spatial displayAsset(AssetOnMap assetOnMap) {
|
||||
int x = assetOnMap.x();
|
||||
int y = assetOnMap.y();
|
||||
@@ -162,6 +231,13 @@ private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOn
|
||||
if (homeNodes.size() > 4) throw new RuntimeException("too many homeNodes for " + color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the rotation angle required to move a piece from one position to another.
|
||||
*
|
||||
* @param prev The previous position.
|
||||
* @param next The target position.
|
||||
* @return The rotation angle in degrees.
|
||||
*/
|
||||
private float getRotationMove(Vector3f prev, Vector3f next) {
|
||||
Vector3f direction = next.subtract(prev).normalizeLocal();
|
||||
//I had to reverse dir.y, because then it worked.
|
||||
@@ -170,6 +246,14 @@ private float getRotationMove(Vector3f prev, Vector3f next) {
|
||||
return newRot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively moves a piece from its current index to the destination index,
|
||||
* to keep track of the piece rotation.
|
||||
*
|
||||
* @param uuid The UUID of the piece to move.
|
||||
* @param curIndex The current index of the piece.
|
||||
* @param moveIndex The target index to move the piece to.
|
||||
*/
|
||||
private void movePieceRek(UUID uuid, int curIndex, int moveIndex){
|
||||
if (curIndex == moveIndex) return;
|
||||
|
||||
@@ -202,6 +286,12 @@ private Vector3f getWaitingPos(Color color){
|
||||
return getMeanPosition(waitingNodesMap.get(color).stream().map(NodeControl::getLocation).toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mean position of a list of vectors.
|
||||
*
|
||||
* @param vectors The list of vectors.
|
||||
* @return The mean position as a Vector3f.
|
||||
*/
|
||||
public static Vector3f getMeanPosition(List<Vector3f> vectors) {
|
||||
if (vectors.isEmpty()) return new Vector3f(0, 0, 0);
|
||||
|
||||
@@ -212,9 +302,14 @@ public static Vector3f getMeanPosition(List<Vector3f> vectors) {
|
||||
return sum.divide(vectors.size());
|
||||
}
|
||||
|
||||
//public methods****************************************************************************************************
|
||||
/**
|
||||
* Adds a player to the game by associating a color and a list of UUIDs to corresponding assets and waiting nodes.
|
||||
*
|
||||
* @param color the color of the player
|
||||
* @param uuid the list of UUIDs representing the player's assets
|
||||
* @throws RuntimeException if the number of assets or waiting nodes does not match the provided UUIDs
|
||||
*/
|
||||
public void addPlayer(Color color, List<UUID> uuid) {
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
|
||||
List<AssetOnMap> playerAssets = colorAssetsMap.get(color);
|
||||
if (playerAssets == null) throw new RuntimeException("Assets for Player color are not defined");
|
||||
@@ -226,20 +321,34 @@ public void addPlayer(Color color, List<UUID> uuid) {
|
||||
|
||||
for (int i = 0; i < playerAssets.size(); i++){
|
||||
AssetOnMap assetOnMap = playerAssets.get(i);
|
||||
UUID pieceUuid = uuid.get(i);
|
||||
|
||||
// Initialize PieceControl
|
||||
PieceControl pieceControl = displayAndControl(assetOnMap, new PieceControl(assetOnMap.rot(), app.getAssetManager(), app, fpp));
|
||||
pieceControl.setRotation(assetOnMap.rot());
|
||||
movePieceToNode(pieceControl, waitNodes.get(i));
|
||||
|
||||
pieces.put(uuid.get(i), pieceControl);
|
||||
// Assign piece to waiting node
|
||||
NodeControl waitNode = getNextWaitingNode(color);
|
||||
waitingNodes.get(color).put(pieceUuid, waitNode);
|
||||
|
||||
pieceColor.put(uuid.get(i), color);
|
||||
// Move piece to node
|
||||
movePieceToNode(pieceControl, waitNode);
|
||||
|
||||
// Update mappings
|
||||
pieces.put(pieceUuid, pieceControl);
|
||||
pieceColor.put(pieceUuid, color);
|
||||
addItemToMapList(waitingPiecesMap, color, pieceControl);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveHomePiece(UUID uuid, int index){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
/**
|
||||
* Moves a piece to its corresponding home node based on the given index.
|
||||
*
|
||||
* @param uuid the UUID of the piece to move
|
||||
* @param index the index of the home node to move the piece to
|
||||
* @throws RuntimeException if the UUID is not mapped to a color or if the home nodes are not properly defined
|
||||
*/
|
||||
private void moveHomePiece(UUID uuid, int index){
|
||||
|
||||
Color color = pieceColor.get(uuid);
|
||||
if(color == null) throw new RuntimeException("uuid is not mapped to a color");
|
||||
@@ -257,90 +366,145 @@ public void moveHomePiece(UUID uuid, int index){
|
||||
NodeControl lastHomeNode = homeNodes.get(homeNodes.size()-1);
|
||||
|
||||
pieceControl.setRotation(getRotationMove(firstHomeNode.getLocation(), lastHomeNode.getLocation()));
|
||||
app.getModelSynchronize().animationEnd();
|
||||
}
|
||||
|
||||
public void movePieceStart(UUID uuid, int nodeIndex){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
/**
|
||||
* Starts the movement of a piece to a target node based on the given index.
|
||||
*
|
||||
* @param uuid the UUID of the piece to move
|
||||
* @param nodeIndex the index of the target node to move the piece to
|
||||
* @throws RuntimeException if the UUID is not mapped to a color or the piece control is not found
|
||||
* @throws IllegalArgumentException if the node index is invalid
|
||||
*/
|
||||
private void movePieceStart(UUID uuid, int nodeIndex){
|
||||
|
||||
// Farbe des Pieces abrufen
|
||||
Color color = pieceColor.get(uuid);
|
||||
if(color == null) throw new RuntimeException("uuid is not mapped to a color");
|
||||
if (color == null) throw new RuntimeException("UUID is not mapped to a color");
|
||||
|
||||
// PieceControl abrufen
|
||||
PieceControl pieceControl = pieces.get(uuid);
|
||||
movePieceToNode(pieceControl, infield.get(nodeIndex));
|
||||
if (pieceControl == null) throw new RuntimeException("PieceControl not found for UUID: " + uuid);
|
||||
|
||||
// Zielknoten abrufen und prüfen
|
||||
if (nodeIndex < 0 || nodeIndex >= infield.size()) {
|
||||
throw new IllegalArgumentException("Invalid nodeIndex: " + nodeIndex);
|
||||
}
|
||||
NodeControl targetNode = infield.get(nodeIndex);
|
||||
|
||||
movePieceToNode(pieceControl, targetNode);
|
||||
|
||||
removeItemFromMapList(waitingPiecesMap, color, pieceControl);
|
||||
waitingNodes.get(color).remove(uuid);
|
||||
app.getModelSynchronize().animationEnd();
|
||||
}
|
||||
|
||||
public void movePiece(UUID uuid, int curIndex, int moveIndex){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
/**
|
||||
* Moves a piece from its current position to the target position based on the given indexes.
|
||||
*
|
||||
* @param uuid the UUID of the piece to move
|
||||
* @param curIndex the current index of the piece
|
||||
* @param moveIndex the target index of the move
|
||||
*/
|
||||
private void movePiece(UUID uuid, int curIndex, int moveIndex){
|
||||
|
||||
movePieceRek(uuid, curIndex, moveIndex);
|
||||
app.getModelSynchronize().animationEnd();
|
||||
}
|
||||
|
||||
public void throwPiece(UUID uuid){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
/**
|
||||
* Throws a piece to the next available waiting node and updates the waiting node mapping.
|
||||
*
|
||||
* @param uuid the UUID of the piece to throw
|
||||
* @throws RuntimeException if the UUID is not mapped to a color or if no available waiting nodes are found
|
||||
*/
|
||||
private void throwPiece(UUID uuid){
|
||||
|
||||
// Farbe des Pieces abrufen
|
||||
Color color = pieceColor.get(uuid);
|
||||
if(color == null) throw new RuntimeException("uuid is not mapped to a color");
|
||||
|
||||
if (color == null) throw new RuntimeException("UUID is not mapped to a color");
|
||||
|
||||
// PieceControl abrufen
|
||||
PieceControl pieceControl = pieces.get(uuid);
|
||||
List<NodeControl> waitNodes = waitingNodesMap.get(color);
|
||||
List<PieceControl> waitPieces = waitingPiecesMap.get(color);
|
||||
if (pieceControl == null) throw new RuntimeException("PieceControl not found for UUID: " + uuid);
|
||||
|
||||
movePieceToNode(pieceControl, waitNodes.get(waitPieces.size()));
|
||||
pieceControl.rotateInit();
|
||||
// Nächste freie Waiting Node abrufen
|
||||
NodeControl nextWaitNode = getNextWaitingNode(color);
|
||||
if (nextWaitNode == null) {
|
||||
throw new IllegalStateException("No available waiting nodes for color: " + color);
|
||||
}
|
||||
|
||||
// Bewegung durchführen
|
||||
movePieceToNode(pieceControl, nextWaitNode);
|
||||
|
||||
// Waiting Nodes aktualisieren
|
||||
waitingNodes.get(color).put(uuid, nextWaitNode);
|
||||
|
||||
// Synchronisation oder Animation
|
||||
pieceControl.rotateInit();
|
||||
app.getModelSynchronize().animationEnd();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Activates the shield for the specified piece.
|
||||
*
|
||||
* @param uuid the UUID of the piece to shield
|
||||
*/
|
||||
public void shieldPiece(UUID uuid){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
|
||||
pieces.get(uuid).activateShield();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the shield for the specified piece.
|
||||
*
|
||||
* @param uuid the UUID of the piece to unshield
|
||||
*/
|
||||
public void unshieldPiece(UUID uuid){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
|
||||
pieces.get(uuid).deactivateShield();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses the shield for the specified piece.
|
||||
*
|
||||
* @param uuid the UUID of the piece to suppress the shield
|
||||
*/
|
||||
public void suppressShield(UUID uuid){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
|
||||
pieces.get(uuid).suppressShield();
|
||||
}
|
||||
|
||||
public void swapPieces(UUID piece1, UUID piece2){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
/**
|
||||
* Swaps the positions and rotations of two pieces.
|
||||
*
|
||||
* @param p1 the first piece to swap
|
||||
* @param p2 the second piece to swap
|
||||
* @param loc1 the original location of the first piece
|
||||
* @param rot1 the original rotation of the first piece
|
||||
* @param loc2 the original location of the second piece
|
||||
* @param rot2 the original rotation of the second piece
|
||||
*/
|
||||
private void swapPieces(PieceControl p1, PieceControl p2, Vector3f loc1, float rot1, Vector3f loc2, float rot2){
|
||||
p1.setLocation(loc2);
|
||||
p2.setLocation(loc1);
|
||||
|
||||
PieceControl piece1Control = pieces.get(piece1);
|
||||
PieceControl piece2Control = pieces.get(piece2);
|
||||
p1.setRotation(rot2);
|
||||
p2.setRotation(rot1);
|
||||
|
||||
if(piece1Control == null) throw new RuntimeException("piece1 UUID is not valid");
|
||||
if(piece2Control == null) throw new RuntimeException("piece2 UUID is not valid");
|
||||
|
||||
float rot1 = piece1Control.getRotation();
|
||||
float rot2 = piece2Control.getRotation();
|
||||
|
||||
piece1Control.setRotation(rot2);
|
||||
piece2Control.setRotation(rot1);
|
||||
|
||||
Vector3f pos1 = piece1Control.getLocation().clone();
|
||||
Vector3f pos2 = piece2Control.getLocation().clone();
|
||||
|
||||
piece1Control.setLocation(pos2);
|
||||
piece2Control.setLocation(pos1);
|
||||
app.getModelSynchronize().animationEnd();
|
||||
}
|
||||
|
||||
public void highlight(UUID uuid, boolean bool){
|
||||
if (!isInitialised) throw new RuntimeException("BoardHandler is not initialized");
|
||||
|
||||
pieces.get(uuid).highlight(bool);
|
||||
pieces.get(uuid).setSelectable(bool);
|
||||
|
||||
}
|
||||
|
||||
//called when (dice) moveNum is received from server to display the movable pieces and corresponding moveNodes
|
||||
/**
|
||||
* Outlines the possible move nodes for a list of pieces based on the move indices and whether it's a home move.
|
||||
*
|
||||
* @param pieces the list of UUIDs representing the pieces to outline
|
||||
* @param moveIndexe the list of indices for the target move nodes
|
||||
* @param homeMoves the list indicating whether the move is a home move
|
||||
* @throws RuntimeException if the sizes of the input lists do not match
|
||||
*/
|
||||
public void outlineMove(List<UUID> pieces, List<Integer> moveIndexe, List<Boolean> homeMoves) {
|
||||
if(pieces.size() != moveIndexe.size() || pieces.size() != homeMoves.size()) throw new RuntimeException("arrays are not the same size");
|
||||
|
||||
@@ -370,7 +534,12 @@ public void outlineMove(List<UUID> pieces, List<Integer> moveIndexe, List<Boolea
|
||||
}
|
||||
}
|
||||
|
||||
//called when swap notification is received to highlight and select own/enemy pieces
|
||||
/**
|
||||
* Outlines the pieces that can be swapped based on the provided own and enemy pieces.
|
||||
*
|
||||
* @param ownPieces the list of UUIDs representing the player's pieces
|
||||
* @param enemyPieces the list of UUIDs representing the enemy's pieces
|
||||
*/
|
||||
public void outlineSwap(List<UUID> ownPieces, List<UUID> enemyPieces){
|
||||
|
||||
selectableEnemyPieces.clear();
|
||||
@@ -394,6 +563,11 @@ public void outlineSwap(List<UUID> ownPieces, List<UUID> enemyPieces){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outlines the pieces that can be shielded based on the provided list of pieces.
|
||||
*
|
||||
* @param pieces the list of UUIDs representing the pieces to be shielded
|
||||
*/
|
||||
public void outlineShield(List<UUID> pieces){
|
||||
selectableOwnPieces.clear();
|
||||
selectableEnemyPieces.clear();
|
||||
@@ -409,7 +583,11 @@ public void outlineShield(List<UUID> pieces){
|
||||
}
|
||||
}
|
||||
|
||||
//called from inputSynchronizer when a piece is selectable
|
||||
/**
|
||||
* Selects a piece from either the own or enemy pieces based on the input and deselects others if needed.
|
||||
*
|
||||
* @param pieceSelected the PieceControl instance representing the piece selected by the user
|
||||
*/
|
||||
public void pieceSelect(PieceControl pieceSelected) {
|
||||
boolean isSelected = pieceSelected.isSelected();
|
||||
if(selectableOwnPieces.contains(pieceSelected)){
|
||||
@@ -443,7 +621,9 @@ else if(selectableEnemyPieces.contains(pieceSelected)) {
|
||||
app.getModelSynchronize().select(getKeyByValue(pieces, selectedOwnPiece), getKeyByValue(pieces, selectedEnemyPiece));
|
||||
}
|
||||
|
||||
//called when view is no longer needed to select pieces
|
||||
/**
|
||||
* Clears all highlighted, selectable, and selected pieces and nodes.
|
||||
*/
|
||||
public void clearSelectable(){
|
||||
for(PieceControl p : selectableEnemyPieces) {
|
||||
p.unSelect();
|
||||
@@ -465,16 +645,20 @@ public void clearSelectable(){
|
||||
selectedOwnPiece = null;
|
||||
}
|
||||
|
||||
public void enableHover(UUID uuid){
|
||||
pieces.get(uuid).setHoverable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the dice for the specified color at the appropriate position.
|
||||
*
|
||||
* @param color the color of the player whose dice should be displayed
|
||||
*/
|
||||
public void showDice(Color color){
|
||||
rootNodeBoard.attachChild(diceControl.getSpatial());
|
||||
diceControl.setPos(getWaitingPos(color).add(new Vector3f(0,0,4)));
|
||||
diceControl.spin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the dice from the view.
|
||||
*/
|
||||
public void hideDice(){
|
||||
diceControl.hide();
|
||||
}
|
||||
@@ -488,4 +672,107 @@ private <K, V> K getKeyByValue(Map<K, V> map, V value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the movement of a piece from its current index to a target index.
|
||||
*
|
||||
* @param uuid the UUID of the piece to animate
|
||||
* @param curIndex the current index of the piece
|
||||
* @param moveIndex the target index to animate the piece to
|
||||
*/
|
||||
public void movePieceAnim(UUID uuid, int curIndex, int moveIndex){
|
||||
pieces.get(uuid).getSpatial().addControl(new MoveControl(
|
||||
infield.get(curIndex).getLocation(),
|
||||
infield.get(moveIndex).getLocation(),
|
||||
()->movePiece(uuid,curIndex,moveIndex)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the movement of a piece to its home position based on the given home index.
|
||||
*
|
||||
* @param uuid the UUID of the piece to animate
|
||||
* @param homeIndex the index of the home node to move the piece to
|
||||
*/
|
||||
public void movePieceHomeAnim(UUID uuid, int homeIndex){
|
||||
pieces.get(uuid).getSpatial().addControl(new MoveControl(
|
||||
pieces.get(uuid).getLocation(),
|
||||
homeNodesMap.get(pieceColor.get(uuid)).get(homeIndex).getLocation(),
|
||||
()->moveHomePiece(uuid,homeIndex)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the start of the movement of a piece to a target index.
|
||||
*
|
||||
* @param uuid the UUID of the piece to animate
|
||||
* @param moveIndex the target index to animate the piece to
|
||||
*/
|
||||
public void movePieceStartAnim(UUID uuid, int moveIndex){
|
||||
pieces.get(uuid).getSpatial().addControl(new MoveControl(
|
||||
pieces.get(uuid).getLocation(),
|
||||
infield.get(moveIndex).getLocation(),
|
||||
()->movePieceStart(uuid, moveIndex)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the throwing of a piece to the next available waiting node.
|
||||
*
|
||||
* @param uuid the UUID of the piece to animate
|
||||
*/
|
||||
public void throwPieceAnim(UUID uuid){
|
||||
pieces.get(uuid).getSpatial().addControl(new MoveControl(
|
||||
pieces.get(uuid).getLocation(),
|
||||
getNextWaitingNode(pieceColor.get(uuid)).getLocation(),
|
||||
()->throwPiece(uuid)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates the swapping of two pieces by swapping their positions and rotations.
|
||||
*
|
||||
* @param piece1 the UUID of the first piece
|
||||
* @param piece2 the UUID of the second piece
|
||||
*/
|
||||
public void swapPieceAnim(UUID piece1, UUID piece2){
|
||||
PieceControl piece1Control = pieces.get(piece1);
|
||||
PieceControl piece2Control = pieces.get(piece2);
|
||||
|
||||
Vector3f loc1 = piece1Control.getLocation().clone();
|
||||
Vector3f loc2 = piece2Control.getLocation().clone();
|
||||
float rot1 = piece1Control.getRotation();
|
||||
float rot2 = piece2Control.getRotation();
|
||||
|
||||
piece1Control.getSpatial().addControl(new MoveControl(
|
||||
piece1Control.getLocation().clone(),
|
||||
piece2Control.getLocation().clone(),
|
||||
()->{}
|
||||
));
|
||||
piece2Control.getSpatial().addControl(new MoveControl(
|
||||
piece2Control.getLocation().clone(),
|
||||
piece1Control.getLocation().clone(),
|
||||
()->swapPieces(piece1Control,piece2Control,loc1,rot1,loc2,rot2)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next available waiting node for the specified color.
|
||||
*
|
||||
* @param color the color of the player to get the next waiting node for
|
||||
* @return the next available NodeControl for the specified color
|
||||
* @throws IllegalStateException if no available waiting nodes are found for the color
|
||||
*/
|
||||
private NodeControl getNextWaitingNode(Color color) {
|
||||
List<NodeControl> nodes = waitingNodesMap.get(color);
|
||||
|
||||
if (nodes == null || nodes.isEmpty()) {
|
||||
throw new IllegalStateException("Keine verfügbaren Warteschleifen-Knoten für die Farbe " + color);
|
||||
}
|
||||
|
||||
for (NodeControl node : nodes) {
|
||||
if (!waitingNodes.getOrDefault(color, new HashMap<>()).containsValue(node)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Keine freien Nodes im Wartebereich für die Farbe " + color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
import pp.mdga.client.MdgaApp;
|
||||
import pp.mdga.game.Color;
|
||||
|
||||
/**
|
||||
* Handles the camera position, rotation, and lighting effects for the game.
|
||||
* Provides methods for camera initialization, updates based on user input, and shutdown operations.
|
||||
*/
|
||||
public class CameraHandler {
|
||||
MdgaApp app;
|
||||
|
||||
@@ -34,6 +38,12 @@ public class CameraHandler {
|
||||
private boolean init;
|
||||
private boolean initRot;
|
||||
|
||||
/**
|
||||
* Constructor for the CameraHandler. Initializes the camera settings and lighting.
|
||||
*
|
||||
* @param app The main application instance that provides the camera and root node.
|
||||
* @param fpp The FilterPostProcessor used for post-processing effects.
|
||||
*/
|
||||
public CameraHandler(MdgaApp app, FilterPostProcessor fpp) {
|
||||
init = false;
|
||||
initRot = false;
|
||||
@@ -61,6 +71,12 @@ public CameraHandler(MdgaApp app, FilterPostProcessor fpp) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the camera with a specific color orientation.
|
||||
* Adds lights, sky, and shadow filters to the scene.
|
||||
*
|
||||
* @param ownColor The color that defines the initial camera view angle.
|
||||
*/
|
||||
public void init(Color ownColor) {
|
||||
app.getRootNode().addLight(sun);
|
||||
app.getRootNode().addLight(ambient);
|
||||
@@ -72,6 +88,10 @@ public void init(Color ownColor) {
|
||||
app.getInputSynchronize().setRotation(getInitAngleByColor(ownColor)*2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the camera handler by removing all lights, sky, and filters,
|
||||
* and resets the camera position and rotation to its default state.
|
||||
*/
|
||||
public void shutdown() {
|
||||
app.getRootNode().removeLight(sun);
|
||||
app.getRootNode().removeLight(ambient);
|
||||
@@ -84,6 +104,13 @@ public void shutdown() {
|
||||
fpp.removeFilter(dlsf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the camera position and rotation based on user input (scroll and rotation).
|
||||
* Adjusts the vertical angle and radius based on zoom and rotation values.
|
||||
*
|
||||
* @param scroll The scroll input, determining zoom level.
|
||||
* @param rotation The rotation input, determining camera orientation.
|
||||
*/
|
||||
public void update(float scroll, float rotation) {
|
||||
if(!init) return;
|
||||
float scrollValue = Math.max(0, Math.min(scroll, 100));
|
||||
@@ -117,6 +144,12 @@ public void update(float scroll, float rotation) {
|
||||
app.getCamera().lookAt(Vector3f.ZERO, Vector3f.UNIT_Z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the camera angle based on the specified color.
|
||||
*
|
||||
* @param color The color used to determine the camera angle.
|
||||
* @return The camera angle in degrees.
|
||||
*/
|
||||
private float getAngleByColor(Color color){
|
||||
return switch (color){
|
||||
case ARMY -> 0;
|
||||
@@ -127,6 +160,12 @@ private float getAngleByColor(Color color){
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initial camera angle based on the specified color.
|
||||
*
|
||||
* @param color The color used to determine the camera angle.
|
||||
* @return The initial camera angle in degrees.
|
||||
*/
|
||||
private float getInitAngleByColor(Color color){
|
||||
return (getAngleByColor(color) + 180) % 360;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,27 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A utility class for loading and parsing map data from a file.
|
||||
* The map contains asset names and coordinates for objects placed on the map.
|
||||
*/
|
||||
class MapLoader {
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private MapLoader() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a map file and parses its contents into a list of assets and their positions.
|
||||
* Each line in the map file defines an asset, its coordinates, and its rotation.
|
||||
*
|
||||
* @param mapName The name of the map file to load. The file is expected to be located in the resources directory.
|
||||
* @return A list of {@link AssetOnMap} objects representing the assets placed on the map.
|
||||
* @throws IOException If an error occurs while reading the map file.
|
||||
* @throws IllegalArgumentException If the map file contains invalid data.
|
||||
*/
|
||||
public static List<AssetOnMap> loadMap(String mapName) {
|
||||
List<AssetOnMap> assetsOnMap = new ArrayList<>();
|
||||
|
||||
@@ -60,6 +76,13 @@ public static List<AssetOnMap> loadMap(String mapName) {
|
||||
return assetsOnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding {@link Asset} for a given asset name.
|
||||
*
|
||||
* @param assetName The name of the asset to load.
|
||||
* @return The {@link Asset} associated with the given name.
|
||||
* @throws IllegalStateException If the asset name is unrecognized.
|
||||
*/
|
||||
private static Asset getLoadedAsset(String assetName) {
|
||||
return switch (assetName) {
|
||||
case "lw" -> Asset.lw;
|
||||
|
||||
@@ -8,19 +8,40 @@
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.mdga.client.MdgaApp;
|
||||
|
||||
/**
|
||||
* A control that adds highlighting functionality to a node in the game.
|
||||
* This class extends {@link OutlineControl} to add an outline effect when the node is highlighted.
|
||||
*/
|
||||
public class NodeControl extends OutlineControl {
|
||||
|
||||
private static final ColorRGBA OUTLINE_HIGHLIGHT_COLOR = ColorRGBA.White;
|
||||
private static final int OUTLINE_HIGHLIGHT_WIDTH = 6;
|
||||
|
||||
/**
|
||||
* Constructs a {@link NodeControl} with the specified application and post processor.
|
||||
* This constructor sets up the necessary elements for highlighting functionality.
|
||||
*
|
||||
* @param app The {@link MdgaApp} instance to use for the application context.
|
||||
* @param fpp The {@link FilterPostProcessor} to apply post-processing effects.
|
||||
*/
|
||||
public NodeControl(MdgaApp app, FilterPostProcessor fpp) {
|
||||
super(app, fpp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the node in 3D space.
|
||||
* This is the node's local translation in the scene.
|
||||
*
|
||||
* @return The {@link Vector3f} representing the node's location.
|
||||
*/
|
||||
public Vector3f getLocation(){
|
||||
return this.getSpatial().getLocalTranslation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights the node by applying an outline effect.
|
||||
* The outline color and width are predefined as white and 6, respectively.
|
||||
*/
|
||||
public void highlight() {
|
||||
super.outline(OUTLINE_HIGHLIGHT_COLOR, OUTLINE_HIGHLIGHT_WIDTH);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.post.FilterPostProcessor;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import pp.mdga.client.MdgaApp;
|
||||
import pp.mdga.client.board.outline.SelectObjectOutliner;
|
||||
import pp.mdga.client.InitControl;
|
||||
import pp.mdga.client.outline.SelectObjectOutliner;
|
||||
|
||||
public class OutlineControl extends AbstractControl {
|
||||
private static final int THICKNESS_DEFAULT = 6;
|
||||
/**
|
||||
* A control that provides outline functionality to a spatial object.
|
||||
* This class is responsible for adding an outline effect to a spatial
|
||||
* object, allowing it to be highlighted or deselected.
|
||||
*/
|
||||
public class OutlineControl extends InitControl {
|
||||
/** The {@link SelectObjectOutliner} responsible for managing the outline effect. */
|
||||
private final SelectObjectOutliner outlineOwn;
|
||||
private static final int THICKNESS_DEFAULT = 6;
|
||||
private MdgaApp app;
|
||||
|
||||
|
||||
@@ -31,44 +34,33 @@ public OutlineControl(MdgaApp app, FilterPostProcessor fpp, Camera cam, int thic
|
||||
outlineOwn = new SelectObjectOutliner(thickness, fpp, app.getRenderManager(), app.getAssetManager(), cam, app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an outline to the spatial object with the given color.
|
||||
*
|
||||
* @param color The {@link ColorRGBA} representing the color of the outline.
|
||||
*/
|
||||
public void outline(ColorRGBA color){
|
||||
outlineOwn.select(spatial, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an outline to the spatial object with the given color and width.
|
||||
*
|
||||
* @param color The {@link ColorRGBA} representing the color of the outline.
|
||||
* @param width The width of the outline.
|
||||
*/
|
||||
public void outline(ColorRGBA color, int width){
|
||||
deOutline();
|
||||
outlineOwn.select(spatial, color, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the outline effect from the spatial object.
|
||||
*/
|
||||
public void deOutline(){
|
||||
outlineOwn.deselect(spatial);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
|
||||
}
|
||||
|
||||
public void initSpatial(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpatial(Spatial spatial){
|
||||
if(this.spatial == null && spatial != null){
|
||||
super.setSpatial(spatial);
|
||||
initSpatial();
|
||||
}
|
||||
else{
|
||||
super.setSpatial(spatial);
|
||||
}
|
||||
}
|
||||
|
||||
public MdgaApp getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
import pp.mdga.client.Asset;
|
||||
import pp.mdga.client.MdgaApp;
|
||||
|
||||
/**
|
||||
* A control that manages the behavior and properties of a game piece, such as its rotation,
|
||||
* position, shield activation, and highlighting. This class extends {@link OutlineControl}
|
||||
* to provide outline functionality and includes additional features like shield effects,
|
||||
* hover states, and selection states.
|
||||
*/
|
||||
public class PieceControl extends OutlineControl {
|
||||
private final float initRotation;
|
||||
private final AssetManager assetManager;
|
||||
@@ -43,7 +49,15 @@ public class PieceControl extends OutlineControl {
|
||||
private boolean selectable;
|
||||
private boolean select;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a {@link PieceControl} with the specified initial rotation, asset manager,
|
||||
* application, and post-processor.
|
||||
*
|
||||
* @param initRotation The initial rotation of the piece in degrees.
|
||||
* @param assetManager The {@link AssetManager} used for loading models and materials.
|
||||
* @param app The {@link MdgaApp} instance to use for the application context.
|
||||
* @param fpp The {@link FilterPostProcessor} to apply post-processing effects.
|
||||
*/
|
||||
public PieceControl(float initRotation, AssetManager assetManager, MdgaApp app, FilterPostProcessor fpp){
|
||||
super(app, fpp);
|
||||
this.parentNode = new Node();
|
||||
@@ -59,10 +73,20 @@ public PieceControl(float initRotation, AssetManager assetManager, MdgaApp app,
|
||||
select = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current rotation of the piece in degrees.
|
||||
*
|
||||
* @return The rotation of the piece in degrees.
|
||||
*/
|
||||
public float getRotation() {
|
||||
return (float) Math.toDegrees(spatial.getLocalRotation().toAngleAxis(new Vector3f(0,0,1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rotation of the piece to the specified value in degrees.
|
||||
*
|
||||
* @param rot The rotation in degrees to set.
|
||||
*/
|
||||
public void setRotation(float rot){
|
||||
if(rot < 0) rot =- 360;
|
||||
|
||||
@@ -71,10 +95,20 @@ public void setRotation(float rot){
|
||||
spatial.setLocalRotation(quaternion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current location (position) of the piece.
|
||||
*
|
||||
* @return The location of the piece as a {@link Vector3f}.
|
||||
*/
|
||||
public Vector3f getLocation(){
|
||||
return spatial.getLocalTranslation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the piece control every frame. If the shield is active, it will rotate.
|
||||
*
|
||||
* @param delta The time difference between frames (time per frame).
|
||||
*/
|
||||
@Override
|
||||
protected void controlUpdate(float delta) {
|
||||
if(shieldRing != null){
|
||||
@@ -82,10 +116,19 @@ protected void controlUpdate(float delta) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location (position) of the piece.
|
||||
*
|
||||
* @param loc The location to set as a {@link Vector3f}.
|
||||
*/
|
||||
public void setLocation(Vector3f loc){
|
||||
this.spatial.setLocalTranslation(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the spatial object and sets its rotation.
|
||||
* This also moves the spatial to a new parent node for organizational purposes.
|
||||
*/
|
||||
@Override
|
||||
public void initSpatial(){
|
||||
setRotation(this.initRotation);
|
||||
@@ -101,6 +144,10 @@ public void rotateInit() {
|
||||
// rotate(rotation - initRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the shield around the piece.
|
||||
* This adds a visual shield effect in the form of a rotating ring.
|
||||
*/
|
||||
public void activateShield(){
|
||||
shieldRing = assetManager.loadModel(Asset.shieldRing.getModelPath());
|
||||
shieldRing.scale(1f);
|
||||
@@ -115,11 +162,18 @@ public void activateShield(){
|
||||
parentNode.attachChild(shieldRing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the shield by removing the shield ring from the scene.
|
||||
*/
|
||||
|
||||
public void deactivateShield(){
|
||||
parentNode.detachChild(shieldRing);
|
||||
shieldRing = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses the shield, changing its color to a suppressed state.
|
||||
*/
|
||||
public void suppressShield(){
|
||||
assert(shieldRing != null) : "PieceControl: shieldRing is not set";
|
||||
shieldMat.setColor("Color", SHIELD_SUPPRESSED_COLOR);
|
||||
@@ -133,22 +187,36 @@ public Material getMaterial(){
|
||||
return ((Geometry) getSpatial()).getMaterial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights the piece with the appropriate outline color based on whether it is an enemy or not.
|
||||
*
|
||||
* @param enemy True if the piece is an enemy, false if it is owned by the player.
|
||||
*/
|
||||
public void highlight(boolean enemy) {
|
||||
this.enemy = enemy;
|
||||
highlight = true;
|
||||
super.outline(enemy ? OUTLINE_ENEMY_COLOR : OUTLINE_OWN_COLOR, OUTLINE_HIGHLIGHT_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the highlight effect from the piece.
|
||||
*/
|
||||
public void unHighlight(){
|
||||
highlight = false;
|
||||
deOutline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a hover effect on the piece if it is hoverable.
|
||||
*/
|
||||
public void hover(){
|
||||
if(!hoverable) return;
|
||||
super.outline(enemy ? OUTLINE_ENEMY_HOVER_COLOR : OUTLINE_OWN_HOVER_COLOR, OUTLINE_HOVER_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the hover effect from the piece.
|
||||
*/
|
||||
public void hoverOff(){
|
||||
if(!hoverable) return;
|
||||
|
||||
@@ -157,28 +225,56 @@ public void hoverOff(){
|
||||
else deOutline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deselects the piece and removes the selection outline. If the piece was highlighted,
|
||||
* it will be re-highlighted. Otherwise, the outline is removed.
|
||||
*/
|
||||
public void unSelect(){
|
||||
select = false;
|
||||
if(highlight) highlight(enemy);
|
||||
else deOutline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the piece and applies the selection outline. If the piece is an enemy, it will
|
||||
* be outlined with the enemy selection color; otherwise, the own selection color will be used.
|
||||
*/
|
||||
public void select(){
|
||||
if(!selectable) return;
|
||||
select = true;
|
||||
super.outline(enemy ? OUTLINE_ENEMY_SELECT_COLOR : OUTLINE_OWN_SELECT_COLOR, OUTLINE_SELECT_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the piece is selectable.
|
||||
*
|
||||
* @param selectable True if the piece can be selected, false otherwise.
|
||||
*/
|
||||
public void setSelectable(boolean selectable){
|
||||
this.selectable = selectable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the piece is selected.
|
||||
*
|
||||
* @return True if the piece is selected, false otherwise.
|
||||
*/
|
||||
public boolean isSelected() { return select; }
|
||||
|
||||
/**
|
||||
* Checks if the piece is selectable.
|
||||
*
|
||||
* @return True if the piece is selectable, false otherwise.
|
||||
*/
|
||||
public boolean isSelectable() {
|
||||
return selectable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the piece is hoverable.
|
||||
*
|
||||
* @param hoverable True if the piece can be hovered over, false otherwise.
|
||||
*/
|
||||
public void setHoverable(boolean hoverable) {
|
||||
this.hoverable = hoverable;
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package pp.mdga.client.board;
|
||||
|
||||
class PileControl {
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package pp.mdga.client.board;
|
||||
|
||||
public enum Rotation {
|
||||
UP,
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
UP_LEFT,
|
||||
UP_RIGHT,
|
||||
DOWN_RIGHT,
|
||||
DOWN_LEFT
|
||||
}
|
||||
@@ -7,22 +7,23 @@
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.system.AppSettings;
|
||||
import pp.mdga.client.Asset;
|
||||
import pp.mdga.client.animation.ZoomControl;
|
||||
import pp.mdga.game.Color;
|
||||
|
||||
public class ActionTextHandler {
|
||||
class ActionTextHandler {
|
||||
private Node root;
|
||||
private BitmapFont font;
|
||||
private AppSettings appSettings;
|
||||
private int ranking;
|
||||
|
||||
public ActionTextHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){
|
||||
ActionTextHandler(Node guiNode, AssetManager assetManager, AppSettings appSettings){
|
||||
root = new Node("actionTextRoot");
|
||||
guiNode.attachChild(root);
|
||||
|
||||
root.setLocalTranslation(center(appSettings.getWidth(), appSettings.getHeight(), Vector3f.ZERO));
|
||||
font = assetManager.loadFont("Fonts/Gunplay.fnt");
|
||||
this.appSettings = appSettings;
|
||||
|
||||
ranking = 0;
|
||||
}
|
||||
|
||||
private Node createTextWithSpacing(String[] textArr, float spacing, float size, ColorRGBA[] colorArr) {
|
||||
@@ -74,48 +75,48 @@ private Vector3f centerText(float width, float height, Vector3f pos){
|
||||
return center(-width, height, pos);
|
||||
}
|
||||
|
||||
public void activePlayer(String name, Color color){
|
||||
void activePlayer(String name, Color color){
|
||||
createTopText(new String[]{name," ist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
public void ownActive(Color color){
|
||||
void ownActive(Color color){
|
||||
createTopText(new String[]{"Du"," bist dran"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
public void diceNum(int diceNum, String name, Color color){
|
||||
void diceNum(int diceNum, String name, Color color){
|
||||
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
|
||||
|
||||
createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 100);
|
||||
|
||||
}
|
||||
|
||||
public void diceNumMult(int diceNum,int mult, String name, Color color){
|
||||
void diceNumMult(int diceNum,int mult, String name, Color color){
|
||||
createTopText(new String[]{name," würfelt:"}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0);
|
||||
|
||||
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 100);
|
||||
}
|
||||
|
||||
public void ownDice(int diceNum){
|
||||
void ownDice(int diceNum){
|
||||
createTopText(String.valueOf(diceNum), 10, 100, ColorRGBA.White, 0);
|
||||
}
|
||||
|
||||
public void ownDiceMult(int diceNum, int mult){
|
||||
void ownDiceMult(int diceNum, int mult){
|
||||
createTopText(new String[]{String.valueOf(diceNum), " x" + mult + " = " + (diceNum*mult)}, 20, 100, new ColorRGBA[]{ColorRGBA.White,ColorRGBA.Red}, 0);
|
||||
}
|
||||
|
||||
public void drawCard(String name, Color color){
|
||||
void drawCard(String name, Color color){
|
||||
createTopText(new String[]{name," erhält eine Bonuskarte"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
public void drawCardOwn(Color color){
|
||||
void drawCardOwn(Color color){
|
||||
createTopText(new String[]{"Du"," erhälst eine Bonuskarte"}, 5,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
public void finishText(String name, Color color){
|
||||
void finishText(String name, Color color){
|
||||
createTopText(new String[]{name," ist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
public void finishTextOwn(Color color){
|
||||
void finishTextOwn(Color color){
|
||||
createTopText(new String[]{"Du", " bist fertig!"}, 7,70, new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, 0).addControl(new ZoomControl());
|
||||
}
|
||||
|
||||
@@ -131,9 +132,25 @@ private ColorRGBA playerColorToColorRGBA(Color color){
|
||||
};
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
void hide(){
|
||||
ranking = 0;
|
||||
root.detachAllChildren();
|
||||
}
|
||||
|
||||
float paddingRanked = 100;
|
||||
|
||||
void rollRankingResult(String name, Color color, int eye){
|
||||
createTopText(new String[]{name,": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking);
|
||||
ranking++;
|
||||
}
|
||||
|
||||
void rollRankingResultOwn(Color color, int eye){
|
||||
createTopText(new String[]{"Du",": "+eye}, 10,90,new ColorRGBA[]{playerColorToColorRGBA(color),ColorRGBA.White}, paddingRanked*ranking);
|
||||
ranking++;
|
||||
}
|
||||
|
||||
void diceNow(){
|
||||
createTopText("Klicke zum Würfeln", 5, 80, ColorRGBA.White, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import com.jme3.texture.Texture2D;
|
||||
import pp.mdga.client.Asset;
|
||||
import pp.mdga.client.MdgaApp;
|
||||
import pp.mdga.client.animation.SymbolControl;
|
||||
import pp.mdga.game.BonusCard;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -67,6 +67,7 @@ public void showRolledDice(int rollNum, Color color) {
|
||||
|
||||
public void showDice() {
|
||||
cardLayerHandler.showDice();
|
||||
actionTextHandler.diceNow();
|
||||
}
|
||||
|
||||
public void hideDice() {
|
||||
@@ -134,5 +135,10 @@ public void finish(Color color){
|
||||
else actionTextHandler.finishText(playerNameHandler.getName(color), color);
|
||||
}
|
||||
|
||||
public void rollRankingResult(Color color, int eye){
|
||||
if(ownColor == color) actionTextHandler.rollRankingResultOwn(color, eye);
|
||||
else actionTextHandler.rollRankingResult(playerNameHandler.getName(color), color, eye);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ public void setActivePlayer(Color color) {
|
||||
}
|
||||
|
||||
public String getName(Color color){
|
||||
if(!colorNameMap.containsKey(color)) throw new RuntimeException("color is not in colorNameMap");
|
||||
return colorNameMap.get(color);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package pp.mdga.client.gui;
|
||||
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
|
||||
public class ZoomControl extends AbstractControl {
|
||||
private boolean zoomingIn = false;
|
||||
private boolean zoomingOut = false;
|
||||
private float progress = 0;
|
||||
private float zoomSpeed = 1f;
|
||||
private float zoomFactor = 1f;
|
||||
|
||||
public ZoomControl() {
|
||||
}
|
||||
|
||||
public ZoomControl(float speed) {
|
||||
zoomSpeed = speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpatial(Spatial spatial) {
|
||||
if (this.spatial == null && spatial != null) {
|
||||
super.setSpatial(spatial);
|
||||
initSpatial();
|
||||
}
|
||||
}
|
||||
|
||||
private void initSpatial() {
|
||||
zoomingIn = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
if (zoomingIn) {
|
||||
progress += tpf * zoomSpeed;
|
||||
if (progress > 1) progress = 1;
|
||||
spatial.setLocalScale(lerp(0, zoomFactor, easeOut(progress)));
|
||||
if (progress >= 1) {
|
||||
zoomingIn = false;
|
||||
zoomingOut = true;
|
||||
progress = 0;
|
||||
}
|
||||
} else if (zoomingOut) {
|
||||
progress += tpf * zoomSpeed;
|
||||
spatial.setLocalScale(lerp(zoomFactor, 0, easeIn(progress)));
|
||||
if (progress > 1) {
|
||||
zoomingOut = false;
|
||||
end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void end() {
|
||||
spatial.removeFromParent();
|
||||
spatial.removeControl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
|
||||
}
|
||||
|
||||
private static float lerp(float start, float end, float t) {
|
||||
return (1 - t) * start + t * end;
|
||||
}
|
||||
|
||||
// private static float easeOut(float t) {
|
||||
// return (float) Math.sqrt(1 - Math.pow(t - 1, 2));
|
||||
// }
|
||||
private float easeOut(float x) {
|
||||
return x == 1 ? 1 : (float) (1 - Math.pow(2, -10 * x));
|
||||
|
||||
}
|
||||
|
||||
// private float easeIn(float t) {
|
||||
// return t * t * t * t;
|
||||
// }
|
||||
private float easeIn(float x) {
|
||||
return x == 0 ? 0 : (float) Math.pow(2, 10 * x - 10);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package pp.mdga.client.board.outline;
|
||||
package pp.mdga.client.outline;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.material.Material;
|
||||
@@ -1,4 +1,4 @@
|
||||
package pp.mdga.client.board.outline;
|
||||
package pp.mdga.client.outline;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.material.Material;
|
||||
@@ -1,4 +1,4 @@
|
||||
package pp.mdga.client.board.outline;
|
||||
package pp.mdga.client.outline;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.material.Material;
|
||||
@@ -1,4 +1,4 @@
|
||||
package pp.mdga.client.board.outline;
|
||||
package pp.mdga.client.outline;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import com.jme3.network.*;
|
||||
import com.jme3.network.serializing.Serializer;
|
||||
import com.jme3.network.serializing.serializers.EnumSerializer;
|
||||
import pp.mdga.game.*;
|
||||
import pp.mdga.message.client.*;
|
||||
import pp.mdga.message.server.*;
|
||||
@@ -12,7 +13,6 @@
|
||||
import java.io.IOException;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
@@ -130,6 +130,7 @@ private void initializeSerializables() {
|
||||
Serializer.registerClass(ReconnectBriefingMessage.class);
|
||||
Serializer.registerClass(ResumeGameMessage.class);
|
||||
Serializer.registerClass(ServerStartGameMessage.class);
|
||||
Serializer.registerClass(ShutdownMessage.class);
|
||||
Serializer.registerClass(StartPieceMessage.class);
|
||||
Serializer.registerClass(UpdateReadyMessage.class);
|
||||
Serializer.registerClass(UpdateTSKMessage.class);
|
||||
@@ -143,6 +144,8 @@ private void initializeSerializables() {
|
||||
Serializer.registerClass(StartNode.class);
|
||||
Serializer.registerClass(PlayerData.class);
|
||||
Serializer.registerClass(HomeNode.class);
|
||||
Serializer.registerClass(PlayerDataMessage.class);
|
||||
Serializer.registerClass(StartBriefingMessage.class);
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
|
||||
@@ -64,6 +64,13 @@ public void onEnter() {
|
||||
app.getViewPort().addProcessor(fpp);
|
||||
|
||||
app.getAcousticHandler().playSound(MdgaSound.START);
|
||||
|
||||
// guiHandler.addPlayer(Color.AIRFORCE, "Cedric");
|
||||
// guiHandler.addPlayer(Color.ARMY, "Ben");
|
||||
// guiHandler.addPlayer(Color.CYBER, "Felix");
|
||||
// guiHandler.addPlayer(Color.NAVY, "Daniel");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -228,7 +228,7 @@ private void toggleTsk(Color color) {
|
||||
app.getModelSynchronize().selectTsk(color);
|
||||
break;
|
||||
case SELF:
|
||||
app.getModelSynchronize().unselectTsk();
|
||||
app.getModelSynchronize().unselectTsk(color);
|
||||
break;
|
||||
case OTHER:
|
||||
//nothing
|
||||
|
||||
@@ -18,7 +18,7 @@ public CeremonyState(ClientState parent, ClientGameLogic logic) {
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
currentState = podiumState;
|
||||
setState(podiumState);
|
||||
logic.addNotification(createCeremonyNotification());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ public void exit() {
|
||||
}
|
||||
|
||||
public void setState(CeremonyStates state){
|
||||
if(this.currentState != null){
|
||||
this.currentState.exit();
|
||||
}
|
||||
state.enter();
|
||||
currentState = state;
|
||||
}
|
||||
|
||||
@@ -190,6 +190,19 @@ public void received(ServerStartGameMessage msg) {
|
||||
state.received(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(ShutdownMessage msg) {state.received(msg);}
|
||||
|
||||
@Override
|
||||
public void received(StartBriefingMessage msg) {
|
||||
state.received(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(PlayerDataMessage msg) {
|
||||
state.received(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(StartPieceMessage msg) {
|
||||
state.received(msg);
|
||||
@@ -236,6 +249,10 @@ public void selectTsk(Color color){
|
||||
state.selectTSK(color);
|
||||
}
|
||||
|
||||
public void deselectTSK(Color color){
|
||||
state.deselectTSK(color);
|
||||
}
|
||||
|
||||
public void selectDice(){
|
||||
state.selectDice();
|
||||
}
|
||||
|
||||
@@ -150,6 +150,9 @@ public void received(ServerStartGameMessage msg) {
|
||||
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(ShutdownMessage msg) {LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);}
|
||||
|
||||
@Override
|
||||
public void received(StartPieceMessage msg) {
|
||||
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
|
||||
@@ -180,6 +183,15 @@ public void received(WaitPieceMessage msg) {
|
||||
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(StartBriefingMessage msg) {
|
||||
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
|
||||
}
|
||||
|
||||
public void received(PlayerDataMessage msg) {
|
||||
LOGGER.log(Level.DEBUG, "Received {0} not allowed.", msg);
|
||||
}
|
||||
|
||||
public void selectPiece(Piece piece) {
|
||||
LOGGER.log(Level.DEBUG, "Selecting piece not allowed.");
|
||||
}
|
||||
|
||||
@@ -30,13 +30,15 @@ public void exit(){
|
||||
|
||||
@Override
|
||||
public void enter(){
|
||||
currentState = startDialogState;
|
||||
setState(startDialogState);
|
||||
ownPlayerID = 0;
|
||||
ownPlayerName = null;
|
||||
}
|
||||
|
||||
public void setState(DialogStates newState){
|
||||
if(currentState != null){
|
||||
currentState.exit();
|
||||
}
|
||||
newState.enter();
|
||||
currentState = newState;
|
||||
}
|
||||
@@ -69,11 +71,6 @@ public StartDialogState getStartDialog() {
|
||||
return startDialogState;
|
||||
}
|
||||
|
||||
public void startGame(){
|
||||
exit();
|
||||
logic.setState(logic.getGameState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectLeave(){
|
||||
currentState.selectLeave();
|
||||
@@ -144,6 +141,16 @@ public void received(ServerStartGameMessage msg){
|
||||
currentState.received(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(PlayerDataMessage msg){
|
||||
currentState.received(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(StartBriefingMessage msg){
|
||||
currentState.received(msg);
|
||||
}
|
||||
|
||||
public DialogStates getState() {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ public class GameState extends ClientState {
|
||||
*/
|
||||
public GameState(ClientState parent, ClientGameLogic logic) {
|
||||
super(parent, logic);
|
||||
state = determineStartPlayerState;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +34,7 @@ public GameState(ClientState parent, ClientGameLogic logic) {
|
||||
*/
|
||||
@Override
|
||||
public void enter() {
|
||||
|
||||
this.setState(this.determineStartPlayerState);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,8 +51,10 @@ public void exit() {
|
||||
* @param newState the state to be set
|
||||
*/
|
||||
public void setState(GameStates newState){
|
||||
state.exit();
|
||||
state.enter();
|
||||
if(this.state != null){
|
||||
this.state.exit();
|
||||
}
|
||||
newState.enter();
|
||||
state = newState;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
import pp.mdga.message.client.*;
|
||||
import pp.mdga.message.server.LobbyPlayerJoinedMessage;
|
||||
import pp.mdga.message.server.LobbyPlayerLeaveMessage;
|
||||
import pp.mdga.message.server.PlayerDataMessage;
|
||||
import pp.mdga.message.server.ServerStartGameMessage;
|
||||
import pp.mdga.message.server.StartBriefingMessage;
|
||||
import pp.mdga.message.server.UpdateReadyMessage;
|
||||
import pp.mdga.message.server.UpdateTSKMessage;
|
||||
import pp.mdga.notification.*;
|
||||
@@ -74,17 +76,26 @@ public void selectStart(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(ServerStartGameMessage msg){
|
||||
public void received(StartBriefingMessage msg){
|
||||
logic.getGame().setBoard(msg.getBoard());
|
||||
logic.addNotification(new GameNotification(logic.getGame().getPlayers().get(parent.getOwnPlayerId()).getColor()));
|
||||
for(Map.Entry<Color, PlayerData> entry : msg.getBoard().getPlayerData().entrySet()){
|
||||
List<UUID> pieceIds = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void received(PlayerDataMessage msg){
|
||||
logic.getGame().getBoard().addPlayerData(msg.getColor(), msg.getPlayerData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(ServerStartGameMessage msg){
|
||||
logic.addNotification(new GameNotification(logic.getGame().getPlayerById(parent.getOwnPlayerId()).getColor()));
|
||||
for (Map.Entry<Color, PlayerData> entry : logic.getGame().getBoard().getPlayerData().entrySet()) {
|
||||
List<UUID> pieceList = new ArrayList<>();
|
||||
for(Piece piece : entry.getValue().getPieces()){
|
||||
pieceIds.add(piece.getUuid());
|
||||
System.out.println(piece.getUuid());
|
||||
pieceList.add(piece.getUuid());
|
||||
}
|
||||
logic.addNotification(new PlayerInGameNotification(entry.getKey(), pieceIds, logic.getGame().getPlayerByColor(entry.getKey()).getName()));
|
||||
logic.addNotification(new PlayerInGameNotification(entry.getKey(), pieceList , logic.getGame().getPlayerByColor(entry.getKey()).getName()));
|
||||
}
|
||||
parent.startGame();
|
||||
logic.setState(logic.getGameState());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,15 +106,20 @@ public void received(LobbyPlayerJoinedMessage msg){
|
||||
if (msg.isHost() && msg.getId() == parent.getOwnPlayerId()){
|
||||
logic.setHost(true);
|
||||
}
|
||||
logic.addNotification(new TskSelectNotification(msg.getPlayer().getColor(), msg.getPlayer().getName(), parent.getOwnPlayerId()== msg.getId()));
|
||||
|
||||
logic.addNotification(new TskSelectNotification(msg.getPlayer().getColor(), msg.getPlayer().getName(), msg.getPlayer().getName().equals(parent.getOwnPlayerName())));
|
||||
logic.getGame().getPlayers().put(msg.getId(), msg.getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(UpdateTSKMessage msg){
|
||||
logic.addNotification(new TskUnselectNotification(logic.getGame().getPlayers().get(msg.getId()).getColor()));
|
||||
logic.getGame().getPlayers().get(msg.getId()).setColor(msg.getColor());
|
||||
if(msg.isTaken()) {
|
||||
logic.addNotification(new TskSelectNotification(msg.getColor(), logic.getGame().getPlayers().get(msg.getId()).getName(), parent.getOwnPlayerId()== msg.getId()));
|
||||
} else {
|
||||
logic.addNotification(new TskUnselectNotification(logic.getGame().getPlayers().get(msg.getId()).getColor()));
|
||||
}
|
||||
|
||||
logic.getGame().getPlayers().get(msg.getId()).setColor(msg.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,34 +14,6 @@ public NetworkDialogState(ClientState parent, ClientGameLogic logic) {
|
||||
this.parent = (DialogsState) parent;
|
||||
}
|
||||
|
||||
private boolean checkIP(String IP){
|
||||
String[] parts = IP.split("\\.");
|
||||
|
||||
// Step 2: Check if there are exactly 4 parts
|
||||
if (parts.length != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 3: Check each part for valid number
|
||||
for (String part : parts) {
|
||||
try {
|
||||
// Step 4: Convert each part into a number
|
||||
int num = Integer.parseInt(part);
|
||||
|
||||
// Step 5: Check whether the number lies in between 0 and 255
|
||||
if (num < 0 || num > 255) {
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// If parsing fails, it's not a valid number
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all checks passed, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public DetermineStartPlayerState(ClientState parent, ClientGameLogic logic) {
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
state = rollRankingDiceState;
|
||||
this.setState(this.rollRankingDiceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,7 +34,9 @@ public void exit() {
|
||||
}
|
||||
|
||||
public void setState(DetermineStartPlayerStates state) {
|
||||
if(this.state != null){
|
||||
this.state.exit();
|
||||
}
|
||||
state.enter();
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public TurnState(ClientState parent, ClientGameLogic logic) {
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
state = powerCardState;
|
||||
this.setState(this.powerCardState);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +40,9 @@ public void exit() {
|
||||
}
|
||||
|
||||
public void setState(TurnStates state){
|
||||
if(this.state != null){
|
||||
this.state.exit();
|
||||
}
|
||||
state.enter();
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import pp.mdga.message.client.RequestDieMessage;
|
||||
import pp.mdga.message.server.DieMessage;
|
||||
import pp.mdga.notification.DiceNowNotification;
|
||||
import pp.mdga.notification.RollDiceNotification;
|
||||
|
||||
public class RollRankingDiceState extends DetermineStartPlayerStates {
|
||||
|
||||
@@ -23,16 +24,17 @@ public void enter() {
|
||||
|
||||
@Override
|
||||
public void exit() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectDice(){
|
||||
System.out.println("selectDice");
|
||||
logic.send(new RequestDieMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(DieMessage msg){
|
||||
logic.addNotification(new RollDiceNotification(logic.getGame().getPlayerById(logic.getDialogs().getOwnPlayerId()).getColor(), msg.getDiceEye(),true));
|
||||
parent.setState(parent.getWaitRanking());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public ChoosePieceState(ClientState parent, ClientGameLogic logic) {
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
currentState = noPieceState;
|
||||
this.setState(this.noPieceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,9 +34,11 @@ public void exit() {
|
||||
}
|
||||
|
||||
public void setState(ChoosePieceStates state){
|
||||
if(currentState != null){
|
||||
currentState.exit();
|
||||
}
|
||||
state.enter();
|
||||
currentState = state;
|
||||
currentState.enter();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,7 +31,7 @@ public PowerCardState(ClientState parent, ClientGameLogic logic) {
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
state = choosePowerCardState;
|
||||
this.setState(this.choosePowerCardState);
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
@@ -40,7 +40,9 @@ public void exit() {
|
||||
}
|
||||
|
||||
public void setState(PowerCardStates state) {
|
||||
if(this.state != null){
|
||||
this.state.exit();
|
||||
}
|
||||
state.enter();
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,9 @@ public Piece(Color color, PieceState state, int id) {
|
||||
}
|
||||
|
||||
private Piece() {
|
||||
color = null;
|
||||
color = Color.NONE;
|
||||
state = PieceState.WAITING;
|
||||
shield = ShieldState.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package pp.mdga.game;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
|
||||
/**
|
||||
* Represents the state of a piece.
|
||||
*/
|
||||
@@ -19,5 +21,21 @@ public enum PieceState {
|
||||
/**
|
||||
* The piece is finished.
|
||||
*/
|
||||
HOMEFINISHED
|
||||
HOMEFINISHED;
|
||||
|
||||
PieceState(){
|
||||
|
||||
}
|
||||
|
||||
public static PieceState getPieceStateByIndex(int index){
|
||||
if (index < 0 || index >= values().length) {
|
||||
throw new IllegalArgumentException("");
|
||||
}
|
||||
return values()[index];
|
||||
}
|
||||
|
||||
|
||||
public PieceState next() {
|
||||
return values()[(ordinal() + 1) % values().length];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,23 @@ public PlayerData(Color color) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
private PlayerData() {
|
||||
homeNodes = null;
|
||||
waitingArea = null;
|
||||
pieces = null;
|
||||
homeNodes = new HomeNode[4];
|
||||
waitingArea = new Piece[4];
|
||||
pieces = new Piece[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be used to check if the player is finished.
|
||||
* ToDo: Currently return always false. Implement logic!
|
||||
*
|
||||
* @return true or false.
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package pp.mdga.game;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
|
||||
/**
|
||||
* Represents the state of a piece's shield.
|
||||
*/
|
||||
@Serializable
|
||||
public enum ShieldState {
|
||||
/**
|
||||
* The shield is not active.
|
||||
@@ -15,5 +18,20 @@ public enum ShieldState {
|
||||
/**
|
||||
* The shield is suppressed, when the piece is on a start node.
|
||||
*/
|
||||
SUPPRESSED
|
||||
SUPPRESSED;
|
||||
|
||||
ShieldState(){
|
||||
|
||||
}
|
||||
|
||||
public static ShieldState getShieldStateByIndex(int index){
|
||||
if (index < 0 || index >= values().length) {
|
||||
throw new IllegalArgumentException("");
|
||||
}
|
||||
return values()[index];
|
||||
}
|
||||
|
||||
public ShieldState next() {
|
||||
return values()[(ordinal() + 1) % values().length];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public StartNode(Color color) {
|
||||
}
|
||||
|
||||
private StartNode() {
|
||||
color = null;
|
||||
color = Color.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package pp.mdga.message.server;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
import pp.mdga.game.Color;
|
||||
import pp.mdga.game.PlayerData;
|
||||
|
||||
@Serializable
|
||||
public class PlayerDataMessage extends ServerMessage{
|
||||
|
||||
private final PlayerData playerData;
|
||||
private final Color color;
|
||||
|
||||
public PlayerDataMessage(PlayerData playerData, Color color){
|
||||
super();
|
||||
this.playerData = playerData;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
private PlayerDataMessage(){
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(ServerInterpreter interpreter) {
|
||||
interpreter.received(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoTextKey() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public PlayerData getPlayerData(){
|
||||
return playerData;
|
||||
}
|
||||
|
||||
public Color getColor(){
|
||||
return color;
|
||||
}
|
||||
}
|
||||
@@ -207,4 +207,15 @@ public interface ServerInterpreter {
|
||||
* @param msg the SelectPiece message received.
|
||||
*/
|
||||
void received(SelectPieceMessage msg);
|
||||
|
||||
/**
|
||||
* Handles a SelectTSK message received from the server.
|
||||
*
|
||||
* @param shutdownMessage the SelectTSK message received.
|
||||
*/
|
||||
void received(ShutdownMessage shutdownMessage);
|
||||
|
||||
void received(StartBriefingMessage msg);
|
||||
|
||||
void received(PlayerDataMessage msg);
|
||||
}
|
||||
|
||||
@@ -8,28 +8,13 @@
|
||||
*/
|
||||
@Serializable
|
||||
public class ServerStartGameMessage extends ServerMessage {
|
||||
/**
|
||||
* Create ServerStartGameMessage attributes.
|
||||
*/
|
||||
private final Board board;
|
||||
|
||||
/**
|
||||
* Constructs a new ServerStartGame instance.
|
||||
*/
|
||||
public ServerStartGameMessage() {
|
||||
super();
|
||||
this.board = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param board as the complete board of this game as a Board object.
|
||||
*/
|
||||
public ServerStartGameMessage(Board board) {
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a visitor to process this message.
|
||||
*
|
||||
@@ -40,15 +25,6 @@ public void accept(ServerInterpreter interpreter) {
|
||||
interpreter.received(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be used to return board attribute of ServerStartGameMessage class.
|
||||
*
|
||||
* @return board as a Board object.
|
||||
*/
|
||||
public Board getBoard() {
|
||||
return this.board;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this message.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package pp.mdga.message.server;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
|
||||
/**
|
||||
* A message sent by the server to inform the clients that the server is shutting down.
|
||||
*/
|
||||
@Serializable
|
||||
public class ShutdownMessage extends ServerMessage {
|
||||
/**
|
||||
* Accepts a visitor to process this message.
|
||||
*
|
||||
* @param interpreter the visitor to process this message
|
||||
*/
|
||||
@Override
|
||||
public void accept(ServerInterpreter interpreter) {
|
||||
interpreter.received(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bundle key of the informational text to be shown at the client.
|
||||
* This key is used to retrieve the appropriate localized text for display.
|
||||
*
|
||||
* @return the bundle key of the informational text
|
||||
*/
|
||||
@Override
|
||||
public String getInfoTextKey() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package pp.mdga.message.server;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
import pp.mdga.game.Board;
|
||||
|
||||
@Serializable
|
||||
public class StartBriefingMessage extends ServerMessage {
|
||||
|
||||
private final Board board;
|
||||
|
||||
public StartBriefingMessage(Board board) {
|
||||
super();
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
private StartBriefingMessage() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public Board getBoard() {
|
||||
return this.board;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(ServerInterpreter interpreter) {
|
||||
interpreter.received(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoTextKey() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -18,23 +18,26 @@ public class UpdateTSKMessage extends ServerMessage {
|
||||
*/
|
||||
private final Color color;
|
||||
|
||||
private final boolean isTaken;
|
||||
|
||||
/**
|
||||
* Constructs a new UpdateTSK instance with the specified id and color.
|
||||
*
|
||||
* @param id the name associated with the update
|
||||
* @param color the color associated with the update
|
||||
*/
|
||||
public UpdateTSKMessage(int id, Color color) {
|
||||
public UpdateTSKMessage(int id, Color color, boolean isTaken) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.color = color;
|
||||
this.isTaken = isTaken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for serialization purposes.
|
||||
*/
|
||||
private UpdateTSKMessage() {
|
||||
this(0, null);
|
||||
this(0, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,4 +87,8 @@ public String toString() {
|
||||
public String getInfoTextKey() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isTaken() {
|
||||
return isTaken;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ public class RollDiceNotification extends Notification{
|
||||
private int eyes;
|
||||
private boolean turbo;
|
||||
private int multiplier;
|
||||
private boolean isRanking;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -22,6 +23,15 @@ public RollDiceNotification(Color color, int eyes) {
|
||||
this.eyes = eyes;
|
||||
this.turbo = false;
|
||||
this.multiplier = -1;
|
||||
this.isRanking = false;
|
||||
}
|
||||
|
||||
public RollDiceNotification(Color color, int eyes, boolean isRanking) {
|
||||
this.color = color;
|
||||
this.eyes = eyes;
|
||||
this.turbo = false;
|
||||
this.multiplier = -1;
|
||||
this.isRanking = isRanking;
|
||||
}
|
||||
|
||||
public RollDiceNotification(Color color, int eyes, boolean turbo, int multiplier) {
|
||||
@@ -29,6 +39,7 @@ public RollDiceNotification(Color color, int eyes, boolean turbo, int multiplier
|
||||
this.eyes = eyes;
|
||||
this.turbo = turbo;
|
||||
this.multiplier = multiplier;
|
||||
this.isRanking = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,4 +65,6 @@ public int getMultiplier() {
|
||||
public boolean isTurbo() {
|
||||
return turbo;
|
||||
}
|
||||
|
||||
public boolean isRanking() { return isRanking; }
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import pp.mdga.message.server.*;
|
||||
import pp.mdga.server.ServerGameLogic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,7 @@ public void initializeGame() {
|
||||
@Override
|
||||
public void received(JoinedLobbyMessage msg, int from) {
|
||||
Player player = new Player(msg.getName());
|
||||
player.setColor(Color.getColorByIndex(this.logic.getGame().getPlayers().size()));
|
||||
player.setColor(Color.NONE);
|
||||
this.logic.getGame().addPlayer(from, player);
|
||||
for (Map.Entry<Integer, Player> entry : this.logic.getGame().getPlayers().entrySet()) {
|
||||
this.logic.getServerSender().broadcast(new LobbyPlayerJoinedMessage(entry.getKey(), entry.getValue(), entry.getKey() == this.logic.getGame().getHost()));
|
||||
@@ -84,8 +85,13 @@ public void received(SelectTSKMessage msg, int from) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.logic.getGame().getPlayerById(from).getColor() != Color.NONE) {
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, this.logic.getGame().getPlayerById(from).getColor(), false));
|
||||
}
|
||||
|
||||
this.logic.getGame().getPlayerById(from).setColor(msg.getColor());
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, msg.getColor()));
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, msg.getColor(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +104,7 @@ public void received(SelectTSKMessage msg, int from) {
|
||||
@Override
|
||||
public void received(DeselectTSKMessage msg, int from) {
|
||||
this.logic.getGame().getPlayerById(from).setColor(Color.NONE);
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, Color.NONE));
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, Color.NONE, false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,6 +116,28 @@ public void received(DeselectTSKMessage msg, int from) {
|
||||
*/
|
||||
@Override
|
||||
public void received(LobbyReadyMessage msg, int from) {
|
||||
//assign a free color
|
||||
if (this.logic.getGame().getPlayerById(from).getColor() == Color.NONE) {
|
||||
ArrayList<Color> colors = new ArrayList<>();
|
||||
colors.add(Color.ARMY);
|
||||
colors.add(Color.AIRFORCE);
|
||||
colors.add(Color.NAVY);
|
||||
colors.add(Color.CYBER);
|
||||
|
||||
for (Map.Entry<Integer, Player> entry : this.logic.getGame().getPlayers().entrySet()) {
|
||||
if (colors.contains(entry.getValue().getColor())) {
|
||||
colors.remove(entry.getValue().getColor());
|
||||
}
|
||||
}
|
||||
|
||||
if (colors.size() < 1) {
|
||||
throw new RuntimeException("can not assign a color");
|
||||
}
|
||||
|
||||
this.logic.getGame().getPlayerById(from).setColor(colors.get(0));
|
||||
this.logic.getServerSender().broadcast(new UpdateTSKMessage(from, colors.get(0), true));
|
||||
}
|
||||
|
||||
this.logic.getGame().getPlayerById(from).setReady(true);
|
||||
this.logic.getServerSender().broadcast(new UpdateReadyMessage(from, true));
|
||||
for (Map.Entry<Integer, Player> entry : this.logic.getGame().getPlayers().entrySet()) {
|
||||
@@ -120,8 +148,12 @@ public void received(LobbyReadyMessage msg, int from) {
|
||||
|
||||
this.logic.getGame().setAllReady(true);
|
||||
if (this.logic.getGame().allReady()) {
|
||||
this.logic.getServerSender().broadcast(new StartBriefingMessage(this.logic.getGame().getBoard()));
|
||||
this.initializeGame();
|
||||
this.logic.getServerSender().broadcast(new ServerStartGameMessage(this.logic.getGame().getBoard()));
|
||||
for (Map.Entry<Color, PlayerData> entry : logic.getGame().getBoard().getPlayerData().entrySet()) {
|
||||
this.logic.getServerSender().broadcast(new PlayerDataMessage(entry.getValue(), entry.getKey()));
|
||||
}
|
||||
this.logic.getServerSender().broadcast(new ServerStartGameMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +180,9 @@ public void received(LobbyNotReadyMessage msg, int from) {
|
||||
*/
|
||||
@Override
|
||||
public void received(LeaveGameMessage msg, int from) {
|
||||
if (from == this.logic.getGame().getHost()) {
|
||||
this.logic.getServerSender().broadcast(new ShutdownMessage());
|
||||
}
|
||||
this.logic.getGame().removePlayer(from);
|
||||
this.logic.getServerSender().broadcast(new LobbyPlayerLeaveMessage(from));
|
||||
this.logic.getServerSender().disconnectClient(from);
|
||||
@@ -164,7 +199,7 @@ public void received(LeaveGameMessage msg, int from) {
|
||||
public void received(StartGameMessage msg, int from) {
|
||||
if (msg.isForceStartGame() || this.logic.getGame().allReady()) {
|
||||
this.initializeGame();
|
||||
this.logic.getServerSender().broadcast(new ServerStartGameMessage(this.logic.getGame().getBoard()));
|
||||
this.logic.getServerSender().broadcast(new ServerStartGameMessage());
|
||||
this.logic.setCurrentState(this.logic.getGameState());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import pp.mdga.message.client.RequestDieMessage;
|
||||
import pp.mdga.message.server.ActivePlayerMessage;
|
||||
import pp.mdga.message.server.DieMessage;
|
||||
import pp.mdga.message.server.EndOfTurnMessage;
|
||||
import pp.mdga.server.ServerGameLogic;
|
||||
import pp.mdga.server.automaton.GameState;
|
||||
|
||||
@@ -69,6 +70,7 @@ public void received(RequestDieMessage msg, int from) {
|
||||
maximumRoll = entry.getValue();
|
||||
} else {
|
||||
this.playersHaveToRoll.remove(entry.getKey());
|
||||
this.logic.getServerSender().send(entry.getKey(), new EndOfTurnMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user