Merge work #7

Merged
fkoppe merged 31 commits from dev/client_koppe into dev/client 2024-11-20 13:50:01 +01:00
187 changed files with 27718 additions and 812 deletions

View File

@@ -6,7 +6,7 @@
<option name="WORKING_DIRECTORY" value="$MODULE_WORKING_DIR$" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="pp.mdga.client.Board.*" />
<option name="PATTERN" value="pp.mdga.client.board.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>

View File

@@ -1,291 +0,0 @@
package pp.mdga.client.Acoustic;
import com.jme3.system.NanoTimer;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
import java.util.*;
public class AcousticHandler {
private MdgaApp app;
private MdgaState state = MdgaState.NONE;
private boolean playGame = false;
private ArrayList<MusicAsset> gameTracks = new ArrayList<>();
private NanoTimer trackTimer = new NanoTimer();
private boolean fading = false;
private NanoTimer fadeTimer = new NanoTimer();
private static final float FADE_DURATION = 3.0f;
private static final float CROSSFADE_DURATION = 1.5f;
private float mainVolume = 1.0f;
private float musicVolume = 1.0f;
private float soundVolume = 1.0f;
private GameMusic scheduled = null;
private GameMusic playing = null;
private ArrayList<GameSound> sounds = new ArrayList<>();
public AcousticHandler(MdgaApp app) {
this.app = app;
}
/**
* This method updates the acousticHandler and should be called every frame
*/
public void update() {
updateVolumeAndTrack();
if (playGame) {
updateGameTracks();
}
Iterator<GameSound> iterator = sounds.iterator();
while (iterator.hasNext()) {
GameSound s = iterator.next();
s.update(getSoundVolumeTotal());
if (!s.isPlaying()) {
iterator.remove();
}
}
}
/**
* This method instantly plays a sound
*
* @param sound the sound to be played
*/
public void playSound(MdgaSound sound) {
ArrayList<SoundAssetDelayVolume> assets = new ArrayList<SoundAssetDelayVolume>();
switch (sound) {
case LOST:
assets.add(new SoundAssetDelayVolume(SoundAsset.LOST, 1.0f, 0.0f));
break;
case VICTORY:
assets.add(new SoundAssetDelayVolume(SoundAsset.VICTORY, 1.0f, 2.0f));
break;
default:
break;
}
for (SoundAssetDelayVolume sawd : assets) {
GameSound gameSound = new GameSound(app, sawd.asset(), getSoundVolumeTotal(), sawd.subVolume(), sawd.delay());
sounds.add(gameSound);
}
}
/**
* This method fades the played music to fit the state.
*
* @param state the state of which the corresponding music should be played to be played
*/
public void playState(MdgaState state) {
if (this.state == state) {
return;
}
MusicAsset asset = null;
switch (state) {
case MAIN:
playGame = false;
asset = MusicAsset.MAIN_MENU;
break;
case LOBBY:
playGame = false;
asset = MusicAsset.LOBBY;
break;
case GAME:
addGameTracks();
playGame = true;
assert (gameTracks.size() > 0) : "no more game music available";
asset = gameTracks.remove(0);
break;
case CEREMONY:
playGame = false;
asset = MusicAsset.CEREMONY;
break;
}
assert (null != asset) : "music sceduling went wrong";
scheduled = new GameMusic(app, asset, getMusicVolumeTotal(), asset.getSubVolume(), asset.getLoop());
}
/**
* Performs linear interpolation between two float values.
*
* @param start The starting value.
* @param end The ending value.
* @param t The interpolation factor, typically between 0 and 1.
* @return The interpolated value between start and end.
*/
private float lerp(float start, float end, float t) {
return start + t * (end - start);
}
/**
* Updates the current volume and handles track crossfading logic.
* This method is responsible for fading out the currently playing track,
* fading in the scheduled track, and handling crossfade between the two tracks.
*/
private void updateVolumeAndTrack() {
if (playing == null && scheduled != null && !fading) {
playing = scheduled;
scheduled = null;
playing.play();
return;
}
if (scheduled != null && !fading) {
fading = true;
fadeTimer.reset();
}
if (fading) {
float time = fadeTimer.getTimeInSeconds();
if (time <= FADE_DURATION) {
float t = Math.min(time / FADE_DURATION, 1.0f);
float oldVolume = lerp(1.0f, 0.0f, t);
if (playing != null) {
playing.update(getMusicVolumeTotal() * oldVolume);
}
}
if (time > FADE_DURATION && time <= FADE_DURATION + CROSSFADE_DURATION) {
float t = Math.min((time - FADE_DURATION) / CROSSFADE_DURATION, 1.0f);
float newVolume = lerp(0.0f, 1.0f, t);
if (!scheduled.isPlaying()) {
scheduled.play();
}
scheduled.update(getMusicVolumeTotal() * newVolume);
}
if (time > FADE_DURATION + CROSSFADE_DURATION) {
if (playing != null) {
playing.pause();
}
playing = scheduled;
scheduled = null;
fading = false;
}
}
else if (playing != null) {
playing.update(getMusicVolumeTotal());
}
}
/**
* Adds a list of game tracks to the gameTracks collection and shuffles them.
* This method adds predefined game tracks to the track list and shuffles the order.
*/
private void addGameTracks() {
Random random = new Random();
for (int i = 1; i <= 6; i++) {
gameTracks.add(MusicAsset.valueOf("GAME_" + i));
}
Collections.shuffle(gameTracks, random);
}
/**
* Updates the current game tracks. If the currently playing track is nearing its end,
* a new track will be scheduled to play. If the list of game tracks is empty, it will be refreshed.
*/
private void updateGameTracks() {
if (playing.nearEnd(10)) {
if (gameTracks.isEmpty()) {
addGameTracks();
}
}
if (playing != null && playing.nearEnd(3) && trackTimer.getTimeInSeconds() > 20) {
trackTimer.reset();
MusicAsset nextTrack = gameTracks.remove(0);
scheduled = new GameMusic(app, nextTrack, getMusicVolumeTotal(), nextTrack.getSubVolume(), nextTrack.getLoop());
}
}
/**
* Retrieves the main volume level.
*
* @return The current main volume level.
*/
public float getMainVolume() {
return mainVolume;
}
/**
* Retrieves the music volume level.
*
* @return The current music volume level.
*/
public float getMusicVolume() {
return musicVolume;
}
/**
* Retrieves the sound volume level.
*
* @return The current sound volume level.
*/
public float getSoundVolume() {
return soundVolume;
}
/**
* Sets the main volume level.
*
* @param mainVolume The desired main volume level.
*/
public void setMainVolume(float mainVolume) {
this.mainVolume = mainVolume;
}
/**
* Sets the music volume level.
*
* @param musicVolume The desired music volume level.
*/
public void setMusicVolume(float musicVolume) {
this.musicVolume = musicVolume;
}
/**
* Sets the sound volume level.
*
* @param soundVolume The desired sound volume level.
*/
public void setSoundVolume(float soundVolume) {
this.soundVolume = soundVolume;
}
/**
* Calculates the total music volume by multiplying the music volume by the main volume.
*
* @return The total music volume.
*/
float getMusicVolumeTotal() {
return getMusicVolume() * getMainVolume();
}
/**
* Calculates the total sound volume by multiplying the sound volume by the main volume.
*
* @return The total sound volume.
*/
float getSoundVolumeTotal() {
return getSoundVolume() * getMainVolume();
}
}

View File

@@ -1,4 +0,0 @@
package pp.mdga.client.Animation;
public enum MdgaAnimation {
}

View File

@@ -1,140 +0,0 @@
package pp.mdga.client.Board;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color;
import java.util.*;
public class BoardView {
private static final float GRID_SIZE = 1.72f;
private static final float GRID_ELEVATION = 0.0f;
private static final String MAP_NAME = "map.mdga";
private final MdgaApp app;
private PileControl drawPile = null;
private PileControl discardPile = null;
private ArrayList<NodeControl> infield = new ArrayList<>(40);
private Map<UUID, PieceControl> pieces;
private Map<Color, List<AssetOnMap>> playerMap;
public BoardView(MdgaApp app) {
assert (app != null) : "app is null";
this.app = app;
this.pieces = new HashMap<>();
this.playerMap = new HashMap<>();
initMap();
initCamera();
}
private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) {
List<AssetOnMap> inMap = playerMap.getOrDefault(col, new ArrayList<>());
inMap.add(assetOnMap);
assert (inMap.size() <= 4) : "to many assets for one player";
playerMap.put(col, inMap);
}
private void initMap() {
List<AssetOnMap> assetOnMaps = MapLoader.loadMap(MAP_NAME);
for (AssetOnMap assetOnMap : assetOnMaps) {
switch (assetOnMap.asset()) {
case lw -> addFigureToPlayerMap(assetToColor(BoardAsset.lw), assetOnMap);
case heer -> addFigureToPlayerMap(assetToColor(BoardAsset.heer), assetOnMap);
case cir -> addFigureToPlayerMap(assetToColor(BoardAsset.cir), assetOnMap);
case marine -> addFigureToPlayerMap(assetToColor(BoardAsset.marine), assetOnMap);
case node_normal, node_bonus, node_start ->
infield.addLast(displayAndControl(assetOnMap, new NodeControl()));
default -> displayAsset(assetOnMap);
}
}
}
private void initCamera() {
app.getFlyByCamera().setEnabled(true);
int zoom = 20;
app.getCamera().setLocation(new Vector3f(-zoom, 0, zoom));
app.getCamera().lookAt(new Vector3f(0, 0, 0), new Vector3f(0, 0, 1));
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(0.3f, 0, -1));
app.getRootNode().addLight(sun);
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
app.getRootNode().addLight(ambient);
int SHADOWMAP_SIZE = 1024 * 8;
DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(app.getAssetManager(), SHADOWMAP_SIZE, 4);
dlsr.setLight(sun);
app.getViewPort().addProcessor(dlsr);
}
private Color assetToColor(BoardAsset asset) {
return switch (asset) {
case lw -> Color.AIRFORCE;
case heer -> Color.ARMY;
case marine -> Color.NAVY;
case cir -> Color.CYBER;
default -> throw new RuntimeException("invalid asset");
};
}
private Spatial createModel(BoardAsset asset, Vector3f pos, float rot) {
String modelName = asset.getModelPath();
String texName = asset.getDiffPath();
Spatial model = app.getAssetManager().loadModel(modelName);
model.scale(asset.getSize());
model.rotate((float) Math.toRadians(0), 0, (float) Math.toRadians(90 + rot));
model.setLocalTranslation(pos);
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat);
app.getRootNode().attachChild(model);
return model;
}
private static Vector3f gridToWorld(int x, int y) {
return new Vector3f(GRID_SIZE * x, GRID_SIZE * y, GRID_ELEVATION);
}
public void addPlayer(Color color, UUID uuid) {
List<AssetOnMap> playerAssets = playerMap.get(color);
assert (playerAssets != null) : "Assets for Player color are not defined";
for (AssetOnMap assetOnMap : playerAssets) {
pieces.put(uuid, displayAndControl(assetOnMap, new PieceControl()));
}
}
//displays an assets and return the created asset
private Spatial displayAsset(AssetOnMap assetOnMap) {
int x = assetOnMap.x();
int y = assetOnMap.y();
return createModel(assetOnMap.asset(), gridToWorld(x, y), assetOnMap.rot());
}
private <T extends AbstractControl> T displayAndControl(AssetOnMap assetOnMap, T control) {
Spatial spatial = displayAsset(assetOnMap);
spatial.addControl(control);
return control;
}
}

View File

@@ -1,18 +0,0 @@
package pp.mdga.client.Board;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
public class PieceControl extends AbstractControl {
@Override
protected void controlUpdate(float v) {
}
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
}
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Board;
class PileControl {
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Dialog;
public class Dialog {
}

View File

@@ -1,26 +0,0 @@
package pp.mdga.client.Dialog;
import pp.dialog.DialogManager;
import pp.mdga.client.MdgaApp;
public class DialogView {
private MdgaApp app;
private DialogManager dialogManager = new DialogManager(app);
private StartDialog dialog;
public DialogView(MdgaApp app) {
this.app = app;
}
DialogManager getDialogManager() {
return dialogManager;
}
public void mainMenu() {
//dialogManager = new DialogManager(app);
//di
//MainMenuDialog mainMenuDialog = new MainMenuDialog(app);
}
}

View File

@@ -1,4 +0,0 @@
package pp.mdga.client.Dialog;
public class InterruptDialog {
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Dialog;
public class MenuDialog {
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Dialog;
public class NetworkDialog {
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Dialog;
public class SoundDialog {
}

View File

@@ -1,34 +0,0 @@
package pp.mdga.client.Dialog;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.dialog.DialogBuilder;
import pp.dialog.SimpleDialog;
import pp.mdga.client.MdgaApp;
public class StartDialog extends SimpleDialog {
StartDialog(MdgaApp app) {
super(app.getDialogView().getDialogManager());
Checkbox serverHost = new Checkbox("sdgfsdg");
serverHost.setChecked(false);
//serverHost.addClickCommands(s -> toggleServerHost());
final Container input = new Container(new SpringGridLayout());
input.addChild(new Label("sdgsgsdg"));
//input.addChild(host, 1);
input.addChild(new Label("sdfdsgsdgsdg"));
//input.addChild(port, 1);
input.addChild(serverHost);
DialogBuilder.simple(app.getDialogView().getDialogManager())
.setTitle("server.dialog")
.setOkButton("button.connect")
.setNoButton("button.cancel")
.setOkClose(false)
.setNoClose(false)
.build(this);
}
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Dialog;
public class VideoDialog {
}

View File

@@ -1,5 +0,0 @@
package pp.mdga.client.Gui;
public class GuiView {
}

View File

@@ -0,0 +1,81 @@
package pp.mdga.client;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.*;
public class InputSyncronizer {
private MdgaApp app;
private InputManager inputManager;
protected boolean rightMousePressed = false;
private float rotationAngle = 0f;
private int scrollValue = 50;
InputSyncronizer(MdgaApp app) {
this.app = app;
this.inputManager = app.getInputManager();
setupInput();
}
public void update() {
rotateModel();
updateScrollValue();
}
private void setupInput() {
inputManager.addMapping("Settings", new KeyTrigger(KeyInput.KEY_ESCAPE));
inputManager.addMapping("RotateRightMouse", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addMapping("MouseLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false)); // Left movement
inputManager.addMapping("MouseRight", new MouseAxisTrigger(MouseInput.AXIS_X, true)); // Right movement
inputManager.addMapping("MouseScrollUp", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false)); // Scroll up
inputManager.addMapping("MouseScrollDown", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true)); // Scroll down
inputManager.addListener(actionListener, "Settings", "RotateRightMouse");
inputManager.addListener(analogListener, "MouseLeft", "MouseRight", "MouseScrollUp", "MouseScrollDown");
}
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("Settings") && isPressed) {
app.getView().pressEscape();
}
if (name.equals("RotateRightMouse")) {
rightMousePressed = isPressed;
}
}
};
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
if (name.equals("MouseLeft") && rightMousePressed) {
rotationAngle -= value * 360f;
rotateModel();
} else if (name.equals("MouseRight") && rightMousePressed) {
rotationAngle += value * 360f;
rotateModel();
} else if (name.equals("MouseScrollUp")) {
scrollValue = Math.min(100, scrollValue + 1);
updateScrollValue();
} else if (name.equals("MouseScrollDown")) {
scrollValue = Math.max(1, scrollValue - 1);
updateScrollValue();
}
}
};
private void rotateModel() {
//System.out.println("Rotation Angle: " + rotationAngle);
}
private void updateScrollValue() {
//System.out.println("Scroll Value: " + scrollValue);
}
}

View File

@@ -1,29 +1,37 @@
package pp.mdga.client;
import com.jme3.app.SimpleApplication;
import com.jme3.system.NanoTimer;
import pp.mdga.client.Acoustic.AcousticHandler;
import pp.mdga.client.Acoustic.MdgaSound;
import pp.mdga.client.Animation.AnimationHandler;
import com.simsilica.lemur.GuiGlobals;
import pp.mdga.client.acoustic.AcousticHandler;
import pp.mdga.client.acoustic.MdgaSound;
import pp.mdga.client.animation.AnimationHandler;
import com.jme3.system.AppSettings;
import pp.mdga.client.Board.BoardView;
import pp.mdga.client.Dialog.DialogView;
import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.view.*;
public class MdgaApp extends SimpleApplication {
private AnimationHandler animationHandler;
private AcousticHandler acousticHandler;
private BoardView boardView;
private DialogView dialogView;
private NotificationSynchronizer notificationSynchronizer;
private InputSyncronizer inputSyncronizer;
NanoTimer test = new NanoTimer();
private MdgaState testState = MdgaState.MAIN;
MdgaView view = null;
private MdgaState state = MdgaState.MAIN;
private static float resolutionFactor = 1;
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setSamples(128);
settings.setCenterWindow(true);
settings.setWidth(1280);
settings.setHeight(720);
int width = (int)(1280 * resolutionFactor);
int height = (int)(720 * resolutionFactor);
settings.setWidth(width);
settings.setHeight(height);
settings.setVSync(false);
MdgaApp app = new MdgaApp();
app.setSettings(settings);
@@ -35,37 +43,49 @@ public static void main(String[] args) {
public void simpleInitApp() {
animationHandler = new AnimationHandler(this);
acousticHandler = new AcousticHandler(this);
boardView = new BoardView(this);
dialogView = new DialogView(this);
notificationSynchronizer = new NotificationSynchronizer(this);
inputSyncronizer = new InputSyncronizer(this);
//dialogView.mainMenu();
//acousticHandler.playState(MdgaState.GAME);
inputManager.deleteMapping("SIMPLEAPP_Exit");
GuiGlobals.initialize(this);
acousticHandler.playSound(MdgaSound.LOST);
acousticHandler.playSound(MdgaSound.VICTORY);
enter(state);
}
@Override
public void simpleUpdate(float tpf) {
inputSyncronizer.update();
view.update();
acousticHandler.update();
}
//test.reset();
if (test.getTimeInSeconds() > 10) {
if (testState == MdgaState.MAIN) {
testState = MdgaState.LOBBY;
acousticHandler.playState(MdgaState.MAIN);
}
else if (testState == MdgaState.LOBBY) {
testState = MdgaState.CEREMONY;
acousticHandler.playState(MdgaState.LOBBY);
}
else {
testState = MdgaState.MAIN;
acousticHandler.playState(MdgaState.CEREMONY);
}
test.reset();
public void enter(MdgaState state) {
if(null != view) {
view.leave();
}
this.state = state;
switch (state) {
case MAIN:
view = new MainView(this);
break;
case LOBBY:
view = new LobbyView(this);
break;
case GAME:
view = new GameView(this);
break;
case CEREMONY:
view = new CeremonyView(this);
break;
case NONE:
throw new RuntimeException("cant enter state NONE");
}
acousticHandler.playState(state);
view.enter();
}
public AnimationHandler getAnimationHandler() {
@@ -76,11 +96,13 @@ public AcousticHandler getAcousticHandler() {
return acousticHandler;
}
public BoardView getBoardView() {
return boardView;
public MdgaState getState() {return state; }
public float getResolutionFactor() {
return resolutionFactor;
}
public DialogView getDialogView() {
return dialogView;
public MdgaView getView() {
return view;
}
}

View File

@@ -5,44 +5,9 @@
import pp.mdga.notification.PlayerInGameNotification;
public enum MdgaState {
NONE {
@Override
void handleNotification(MdgaApp app, Notification notification) {
throw new RuntimeException("unexpected notification");
}
},
MAIN {
@Override
void handleNotification(MdgaApp app, Notification notification) {
throw new RuntimeException("unexpected notification");
}
},
LOBBY {
@Override
void handleNotification(MdgaApp app, Notification notification) {
throw new RuntimeException("unexpected notification");
}
},
GAME {
@Override
void handleNotification(MdgaApp app, Notification notification) {
if (notification instanceof PlayerInGameNotification) {
//TODO
}
else if (notification instanceof PieceInGameNotification) {
//TODO
}
else {
throw new RuntimeException("unexpected notification");
}
}
},
CEREMONY {
@Override
void handleNotification(MdgaApp app, Notification notification) {
throw new RuntimeException("unexpected notification");
}
};
abstract void handleNotification(MdgaApp app, Notification notification);
NONE,
MAIN,
LOBBY,
GAME,
CEREMONY;
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class ModelSyncronizer {
}

View File

@@ -1,12 +1,11 @@
package pp.mdga.client;
import pp.mdga.notification.Notification;
import pp.mdga.notification.*;
import java.util.ArrayList;
public class NotificationSynchronizer {
private final MdgaApp app;
private MdgaState state = MdgaState.MAIN;
NotificationSynchronizer(MdgaApp app) {
this.app = app;
@@ -17,7 +16,104 @@ void update() {
//TODO fetch model notifications
for (Notification n : notifications) {
state.handleNotification(app, n);
switch (app.getState()) {
case MAIN:
handleMain(n);
break;
case LOBBY:
handleLobby(n);
break;
case GAME:
handleGame(n);
break;
case CEREMONY:
handleCeremony(n);
break;
case NONE:
throw new RuntimeException("no notification expected: " + n.toString());
}
}
}
private void handleMain(Notification notification) {
if (notification instanceof LobbyDialogNotification) {
app.enter(MdgaState.LOBBY);
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
}
}
private void handleLobby(Notification notification) {
if (notification instanceof TskSelectNotification) {
} else if (notification instanceof TskUnselectNotification) {
} else if (notification instanceof GameNotification) {
app.enter(MdgaState.GAME);
} else if (notification instanceof InterruptNotification) {
//TODO gibt es einen intterupt in der lobby?????
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
}
}
private void handleGame(Notification notification) {
if (notification instanceof AcquireCardNotification) {
// Handle AcquireCardNotification
} else if (notification instanceof ActivePlayerNotification) {
// Handle ActivePlayerNotification
} else if (notification instanceof CeremonyNotification) {
app.enter(MdgaState.CEREMONY);
} else if (notification instanceof DiceNowNotification) {
// Handle DiceNowNotification
} else if (notification instanceof DicingNotification) {
// Handle DicingNotification
} else if (notification instanceof DrawCardNotification) {
// Handle DrawCardNotification
} else if (notification instanceof HomeMoveNotification) {
// Handle HomeMoveNotification
} else if (notification instanceof InterruptNotification) {
// Handle InterruptNotification
} else if (notification instanceof MovePieceNotification) {
// Handle MovePieceNotification
} else if (notification instanceof MoveThrowPieceNotification) {
// Handle MoveThrowPieceNotification
} else if (notification instanceof NoShieldNotification) {
// Handle NoShieldNotification
} else if (notification instanceof PieceInGameNotification) {
// Handle PieceInGameNotification
} else if (notification instanceof PlayCardNotification) {
// Handle PlayCardNotification
} else if (notification instanceof PlayerInGameNotification) {
// Handle PlayerInGameNotification
} else if (notification instanceof ResumeNotification) {
// Handle ResumeNotification
} else if (notification instanceof RollDiceNotification) {
// Handle RollDiceNotification
} else if (notification instanceof SelectableCardsNotification) {
// Handle SelectableCardsNotification
} else if (notification instanceof SelectablePiecesNotification) {
// Handle SelectablePiecesNotification
} else if (notification instanceof ShieldActiveNotification) {
// Handle ShieldActiveNotification
} else if (notification instanceof ShieldSuppressedNotification) {
// Handle ShieldSuppressedNotification
} else if (notification instanceof StartDialogNotification) {
// Handle StartDialogNotification
} else if (notification instanceof SwapPieceNotification) {
// Handle SwapPieceNotification
} else if (notification instanceof WaitMoveNotification) {
// Handle WaitMoveNotification
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
}
}
private void handleCeremony(Notification notification) {
if (notification instanceof StartDialogNotification) {
app.enter(MdgaState.MAIN);
} else {
throw new RuntimeException("notification not expected: " + notification.toString());
}
}
}

View File

@@ -0,0 +1,403 @@
package pp.mdga.client.acoustic;
import com.jme3.system.NanoTimer;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
import java.util.*;
public class AcousticHandler {
private MdgaApp app;
private MdgaState state = MdgaState.NONE;
private boolean playGame = false;
private ArrayList<MusicAsset> gameTracks = new ArrayList<>();
private NanoTimer trackTimer = new NanoTimer();
private boolean fading = false; // Indicates if a fade is in progress
private NanoTimer fadeTimer = new NanoTimer(); // Timer to track fade progress
private static final float FADE_DURATION = 3.0f; // Duration for outfade
private static final float CROSSFADE_DURATION = 1.5f; // Duration for infade
private GameMusic playing = null; // Currently playing track
private GameMusic scheduled = null; // Scheduled track to play next
private GameMusic old = null; // Old track being faded out
private float mainVolume = 1.0f;
private float musicVolume = 1.0f;
private float soundVolume = 1.0f;
private ArrayList<GameSound> sounds = new ArrayList<>();
public AcousticHandler(MdgaApp app) {
this.app = app;
}
/**
* This method updates the acousticHandler and should be called every frame
*/
public void update() {
updateVolumeAndTrack();
if (playGame) {
updateGameTracks();
}
Iterator<GameSound> iterator = sounds.iterator();
while (iterator.hasNext()) {
GameSound s = iterator.next();
s.update(getSoundVolumeTotal());
if (!s.isPlaying()) {
iterator.remove();
}
}
}
/**
* This method instantly plays a sound
*
* @param sound the sound to be played
*/
public void playSound(MdgaSound sound) {
ArrayList<SoundAssetDelayVolume> assets = new ArrayList<SoundAssetDelayVolume>();
switch (sound) {
case LOST:
assets.add(new SoundAssetDelayVolume(SoundAsset.LOST, 1.0f, 0.0f));
break;
case VICTORY:
assets.add(new SoundAssetDelayVolume(SoundAsset.VICTORY, 1.0f, 2.0f));
break;
default:
break;
}
for (SoundAssetDelayVolume sawd : assets) {
GameSound gameSound = new GameSound(app, sawd.asset(), getSoundVolumeTotal(), sawd.subVolume(), sawd.delay());
sounds.add(gameSound);
}
}
/**
* This method fades the played music to fit the state.
*
* @param state the state of which the corresponding music should be played to be played
*/
public void playState(MdgaState state) {
if (this.state == state) {
return;
}
MusicAsset asset = null;
switch (state) {
case MAIN:
playGame = false;
asset = MusicAsset.MAIN_MENU;
break;
case LOBBY:
playGame = false;
asset = MusicAsset.LOBBY;
break;
case GAME:
addGameTracks();
playGame = true;
assert (!gameTracks.isEmpty()) : "no more game music available";
asset = gameTracks.removeFirst();
break;
case CEREMONY:
playGame = false;
asset = MusicAsset.CEREMONY;
break;
case NONE:
throw new RuntimeException("no music for state NONE");
}
assert (null != asset) : "music sceduling went wrong";
scheduled = new GameMusic(app, asset, getMusicVolumeTotal(), asset.getSubVolume(), asset.getLoop(), 0.0f);
}
/**
* Performs linear interpolation between two float values.
*
* @param start The starting value.
* @param end The ending value.
* @param t The interpolation factor, typically between 0 and 1.
* @return The interpolated value between start and end.
*/
private float lerp(float start, float end, float t) {
return start + t * (end - start);
}
/**
* Updates the state of audio playback, handling track transitions and volume adjustments.
*
* This method ensures smooth transitions between tracks using fade-in and fade-out effects.
* It also handles cases where no track is playing, starting a scheduled track immediately at full volume.
* The method prioritizes the latest scheduled track if multiple scheduling occurs quickly.
*
* Behavior:
* 1. If nothing is scheduled and no track is playing, it exits early.
* 2. If a scheduled track exists and no track is playing, the scheduled track starts immediately at full volume.
* 3. If a scheduled track exists while a track is playing, it initiates a fade-out for the currently playing track
* and prepares for the new track to fade in.
* 4. If a track transition is in progress (fading), it processes the fade-out and fade-in states.
* If a new track is scheduled during this process, it interrupts the current transition and prioritizes the new track.
* 5. If no fading is needed and a track is playing, it ensures the track's volume is updated.
*
* Special cases:
* - If no track is playing and a new track is scheduled, it starts the track immediately without fading.
* - If a new track is scheduled during fading, it resets the transition to prioritize the new track.
*/
private void updateVolumeAndTrack() {
if (scheduled == null && !fading && playing == null) {
// Nothing to do, early exit
return;
}
if (scheduled != null && playing == null && !fading) {
// No current track, start scheduled track immediately at full volume
playing = scheduled;
scheduled = null;
playing.play();
playing.update(getMusicVolumeTotal()); // Set volume to full
return;
}
if (scheduled != null && !fading) {
// Initiate a fade process if a new track is scheduled
fading = true;
fadeTimer.reset();
old = playing; // The currently playing track becomes the old track
playing = null; // Clear the playing track during the fade process
}
if (fading) {
handleFadeProcess();
// Handle any interruptions due to newly scheduled tracks
if (scheduled != null && playing != null && playing != scheduled) {
// Interrupt the current infade and switch to the new scheduled track
old = playing; // Treat the currently infading track as the old track
playing = null; // Reset playing to allow switching
fadeTimer.reset(); // Restart fade timer for the new track
}
} else if (playing != null) {
// Update volume for the currently playing track
playing.update(getMusicVolumeTotal());
} else if (scheduled != null) {
// If no track is playing and one is scheduled, start it immediately at full volume
playing = scheduled;
scheduled = null;
playing.play();
playing.update(getMusicVolumeTotal()); // Set volume to full
}
}
/**
* Manages the fading process during audio track transitions.
*
* This method handles the fade-out of the currently playing (old) track, manages any pause between the fade-out
* and fade-in, and initiates the fade-in for the new track if applicable. It ensures smooth transitions between
* tracks while maintaining the correct volume adjustments.
*
* Behavior:
* 1. **Outfade:** Gradually decreases the volume of the `old` track over the duration of `FADE_DURATION`.
* Once the outfade completes, the `old` track is paused and cleared.
* 2. **Pause Handling:** Waits for a defined pause (if applicable) before initiating the infade for the next track.
* 3. **Infade:** If a `scheduled` track exists and the outfade and pause are complete, it begins playing
* the new track (`playing`) and initiates the infade process.
*
* Key Details:
* - The outfade volume adjustment is interpolated linearly from full volume to zero using the `lerp` function.
* - The pause duration is retrieved from the scheduled track if it is specified.
* - If a new track is scheduled during the fade process, it is handled by external logic to prioritize transitions.
*
* Preconditions:
* - `fading` is expected to be `true` when this method is called.
* - The method is invoked as part of the `updateVolumeAndTrack` process.
*/
private void handleFadeProcess() {
float time = fadeTimer.getTimeInSeconds();
// Handle outfade for the old track
if (old != null && time <= FADE_DURATION) {
float t = Math.min(time / FADE_DURATION, 1.0f);
float oldVolume = lerp(1.0f, 0.0f, t);
old.update(getMusicVolumeTotal() * oldVolume);
}
if (old != null && time > FADE_DURATION) {
// Complete outfade
old.pause();
old = null;
}
// Handle pause duration before infade
float pause = (scheduled != null) ? scheduled.getPause() : 0.0f;
if (time > FADE_DURATION + pause) {
if (playing == null && scheduled != null) {
// Begin infade for the new track
playing = scheduled;
scheduled = null;
playing.play(); // Start playing the new track
}
handleInfade(time - FADE_DURATION - pause);
}
}
/**
* Manages the fade-in process for the currently playing track.
*
* This method gradually increases the volume of the `playing` track from zero to full volume
* over the duration of `CROSSFADE_DURATION`. It ensures a smooth transition into the new track.
*
* Behavior:
* 1. If no track is set as `playing`, the method exits early, as there is nothing to fade in.
* 2. Linearly interpolates the volume of the `playing` track from 0.0 to 1.0 based on the elapsed
* `infadeTime` and the specified `CROSSFADE_DURATION`.
* 3. Once the fade-in is complete (when `infadeTime` exceeds `CROSSFADE_DURATION`), the method:
* - Marks the fade process (`fading`) as complete.
* - Ensures the `playing` track is updated to its full volume.
*
* Key Details:
* - Uses the `lerp` function to calculate the volume level for the `playing` track during the fade-in.
* - Ensures the volume is always a value between 0.0 and 1.0.
* - The `infadeTime` parameter should be relative to the start of the fade-in process.
*
* Preconditions:
* - The `playing` track must be initialized and actively fading in for this method to have an effect.
* - The method is invoked as part of the `updateVolumeAndTrack` process.
*
* @param infadeTime The elapsed time (in seconds) since the fade-in process started.
*/
private void handleInfade(float infadeTime) {
if (playing == null) {
// Nothing to infade
return;
}
// Proceed with the infade for the current playing track
float t = Math.min(infadeTime / CROSSFADE_DURATION, 1.0f);
float newVolume = lerp(0.0f, 1.0f, t);
playing.update(getMusicVolumeTotal() * newVolume);
if (infadeTime > CROSSFADE_DURATION) {
// Infade is complete, finalize state
fading = false;
playing.update(getMusicVolumeTotal()); // Ensure full volume
}
}
/**
* Adds a list of game tracks to the gameTracks collection and shuffles them.
* This method adds predefined game tracks to the track list and shuffles the order.
*/
private void addGameTracks() {
Random random = new Random();
for (int i = 1; i <= 6; i++) {
gameTracks.add(MusicAsset.valueOf("GAME_" + i));
}
Collections.shuffle(gameTracks, random);
}
/**
* Updates the current game tracks. If the currently playing track is nearing its end,
* a new track will be scheduled to play. If the list of game tracks is empty, it will be refreshed.
*/
private void updateGameTracks() {
if(null == playing) {
return;
}
if (playing.nearEnd(10)) {
if (gameTracks.isEmpty()) {
addGameTracks();
}
}
if (playing != null && playing.nearEnd(3) && trackTimer.getTimeInSeconds() > 20) {
trackTimer.reset();
MusicAsset nextTrack = gameTracks.remove(0);
scheduled = new GameMusic(app, nextTrack, getMusicVolumeTotal(), nextTrack.getSubVolume(), nextTrack.getLoop(), 0.0f);
}
}
/**
* Retrieves the main volume level.
*
* @return The current main volume level.
*/
public float getMainVolume() {
return mainVolume;
}
/**
* Retrieves the music volume level.
*
* @return The current music volume level.
*/
public float getMusicVolume() {
return musicVolume;
}
/**
* Retrieves the sound volume level.
*
* @return The current sound volume level.
*/
public float getSoundVolume() {
return soundVolume;
}
/**
* Sets the main volume level.
*
* @param mainVolume The desired main volume level.
*/
public void setMainVolume(float mainVolume) {
this.mainVolume = mainVolume;
}
/**
* Sets the music volume level.
*
* @param musicVolume The desired music volume level.
*/
public void setMusicVolume(float musicVolume) {
this.musicVolume = musicVolume;
}
/**
* Sets the sound volume level.
*
* @param soundVolume The desired sound volume level.
*/
public void setSoundVolume(float soundVolume) {
this.soundVolume = soundVolume;
}
/**
* Calculates the total music volume by multiplying the music volume by the main volume.
*
* @return The total music volume.
*/
float getMusicVolumeTotal() {
return getMusicVolume() * getMainVolume();
}
/**
* Calculates the total sound volume by multiplying the sound volume by the main volume.
*
* @return The total sound volume.
*/
float getSoundVolumeTotal() {
return getSoundVolume() * getMainVolume();
}
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
@@ -14,6 +14,7 @@ class GameMusic {
private float volume;
private final float subVolume;
private final AudioNode music;
private float pause;
/**
* Constructs a new GameMusic object.
@@ -24,9 +25,10 @@ class GameMusic {
* @param subVolume A relative volume that modifies the base music volume, typically a percentage.
* @param loop A flag indicating whether the music should loop once it finishes.
*/
GameMusic(MdgaApp app, MusicAsset asset, float volume, float subVolume, boolean loop) {
GameMusic(MdgaApp app, MusicAsset asset, float volume, float subVolume, boolean loop, float pause) {
this.volume = volume;
this.subVolume = subVolume;
this.pause = pause;
music = new AudioNode(app.getAssetManager(), asset.getPath(), AudioData.DataType.Stream);
music.setPositional(false);
@@ -107,4 +109,8 @@ void update(float newVolume) {
music.setVolume(volume * subVolume);
}
}
float getPause() {
return pause;
}
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
/**
* Enum representing the various sound effects used in the game.

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
/**
* Enum representing various music assets used in the game.
@@ -7,15 +7,15 @@
* These music assets are used to control the music that plays in different parts of the game, such as menus and in-game music.
*/
enum MusicAsset {
MAIN_MENU("Spaceship.wav", 1.0f),
LOBBY("DeadPlanet.wav", 1.0f),
CEREMONY("80s,Disco,Life.wav", 1.0f),
GAME_1("NeonRoadTrip.wav", false, 1.0f),
GAME_2("NoPressureTrance.wav", false, 1.0f),
GAME_3("TheSynthRave.wav", false, 1.0f),
GAME_4("LaserParty.wav", false, 1.0f),
GAME_5("RetroNoir.wav", false, 1.0f),
GAME_6("SpaceInvaders.wav", false, 1.0f);
MAIN_MENU("Spaceship.wav", true, 1.0f),
LOBBY("DeadPlanet.wav", true, 1.0f),
CEREMONY("80s,Disco,Life.wav", true, 1.0f),
GAME_1("NeonRoadTrip.wav", 1.0f),
GAME_2("NoPressureTrance.wav", 1.0f),
GAME_3("TheSynthRave.wav", 1.0f),
GAME_4("LaserParty.wav", 1.0f),
GAME_5("RetroNoir.wav", 1.0f),
GAME_6("SpaceInvaders.wav", 1.0f);
private final String path;
private final boolean loop;

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
/**
* Enum representing various sound assets used in the game.

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Acoustic;
package pp.mdga.client.acoustic;
/**
* A record that encapsulates a sound asset along with its playback settings:

View File

@@ -1,6 +1,7 @@
package pp.mdga.client.Animation;
package pp.mdga.client.animation;
abstract class Animation {
abstract void play();
abstract void stop();

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Animation;
package pp.mdga.client.animation;
import pp.mdga.client.MdgaApp;

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Animation;
package pp.mdga.client.animation;
class EmptyAnimation extends Animation {
@Override

View File

@@ -0,0 +1,4 @@
package pp.mdga.client.animation;
public enum MdgaAnimation {
}

View File

@@ -1,3 +1,3 @@
package pp.mdga.client.Board;
package pp.mdga.client.board;
record AssetOnMap(BoardAsset asset, int x, int y, float rot) {}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Board;
package pp.mdga.client.board;
enum BoardAsset {
bigTent,
@@ -9,20 +9,28 @@ enum BoardAsset {
lw,
marine,
node_home_blue("./node_home/node_home.j3o", "./node_home/node_home_blue_diff.png"),
node_wait_blue("./node_home/node_home.j3o", "./node_home/node_home_blue_diff.png"),
node_home_black("./node_home/node_home.j3o", "./node_home/node_home_black_diff.png"),
node_wait_black("./node_home/node_home.j3o", "./node_home/node_home_black_diff.png"),
node_home_green("./node_home/node_home.j3o", "./node_home/node_home_green_diff.png"),
node_wait_green("./node_home/node_home.j3o", "./node_home/node_home_green_diff.png"),
node_home_yellow("./node_home/node_home.j3o", "./node_home/node_home_yellow_diff.png"),
node_wait_yellow("./node_home/node_home.j3o", "./node_home/node_home_yellow_diff.png"),
node_normal,
node_start("./node_normal/node_normal.j3o", "./node_normal/node_start_diff.png"),
node_bonus("./node_normal/node_normal.j3o", "./node_normal/node_bonus_diff.png"),
radar,
shieldCard,
ship,
ship(0.8f),
smallTent,
swapCard,
tank,
turboCard,
world(1.2f);
// world(1.2f),
world("./world_new/world_new.obj", "./world_new/world_new_diff.png", 1.2f),
shield_ring("./shield_ring/shield_ring.obj", null),
tree_small("./tree_small/tree_small.obj", "./tree_small/tree_small_diff.png"),
tree_big("./tree_big/tree_big.obj", "./tree_big/tree_big_diff.png");
private final String modelPath;
private final String diffPath;
@@ -48,6 +56,12 @@ enum BoardAsset {
this.size = size;
}
BoardAsset(String modelPath, String diffPath, float size){
this.modelPath = modelPath;
this.diffPath = diffPath;
this.size = size;
}
public String getModelPath() {
return modelPath;
}

View File

@@ -0,0 +1,291 @@
package pp.mdga.client.board;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import pp.mdga.client.MdgaApp;
import pp.mdga.game.Color;
import java.util.*;
public class BoardHandler {
private static final float GRID_SIZE = 1.72f;
private static final float GRID_ELEVATION = 0.0f;
private static final String MAP_NAME = "map.mdga";
private final MdgaApp app;
private PileControl drawPile = null;
private PileControl discardPile = null;
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<UUID, Color> pieceColor;
private Node node = new Node();
public BoardHandler(MdgaApp app) {
assert (app != null) : "app is null";
this.app = app;
this.pieces = new HashMap<>();
this.colorAssetsMap = new HashMap<>();
this.infield = new ArrayList<>(40);
this.homeNodesMap = new HashMap<>();
this.waitingNodesMap = new HashMap<>();
this.waitingPiecesMap = new HashMap<>();
this.pieceColor = new HashMap<>();
initMap();
}
public void init() {
app.getRootNode().attachChild(node);
}
public void shutdown() {
app.getRootNode().detachChild(node);
}
private void addFigureToPlayerMap(Color col, AssetOnMap assetOnMap) {
List<AssetOnMap> inMap = addItemToMapList(colorAssetsMap, col, assetOnMap);
assert (inMap.size() <= 4) : "BoardView: to many assets for " + col;
}
private void initMap() {
List<AssetOnMap> assetOnMaps = MapLoader.loadMap(MAP_NAME);
for (AssetOnMap assetOnMap : assetOnMaps) {
switch (assetOnMap.asset()) {
case lw -> addFigureToPlayerMap(assetToColor(BoardAsset.lw), assetOnMap);
case heer -> addFigureToPlayerMap(assetToColor(BoardAsset.heer), assetOnMap);
case cir -> addFigureToPlayerMap(assetToColor(BoardAsset.cir), assetOnMap);
case marine -> addFigureToPlayerMap(assetToColor(BoardAsset.marine), assetOnMap);
case node_normal, node_bonus, node_start ->
infield.add(displayAndControl(assetOnMap, new NodeControl()));
case node_home_black -> addHomeNode(homeNodesMap, Color.AIRFORCE, assetOnMap);
case node_home_blue -> addHomeNode(homeNodesMap, Color.NAVY, assetOnMap);
case node_home_green -> addHomeNode(homeNodesMap, Color.ARMY, assetOnMap);
case node_home_yellow -> addHomeNode(homeNodesMap, Color.CYBER, assetOnMap);
case node_wait_black -> addHomeNode(waitingNodesMap, Color.AIRFORCE, assetOnMap);
case node_wait_blue -> addHomeNode(waitingNodesMap, Color.NAVY, assetOnMap);
case node_wait_green -> addHomeNode(waitingNodesMap, Color.ARMY, assetOnMap);
case node_wait_yellow -> addHomeNode(waitingNodesMap, Color.CYBER, assetOnMap);
default -> displayAsset(assetOnMap);
}
}
}
private Color assetToColor(BoardAsset asset) {
return switch (asset) {
case lw -> Color.AIRFORCE;
case heer -> Color.ARMY;
case marine -> Color.NAVY;
case cir -> Color.CYBER;
default -> throw new RuntimeException("invalid asset");
};
}
private Spatial createModel(BoardAsset asset, Vector3f pos, float rot) {
String modelName = asset.getModelPath();
String texName = asset.getDiffPath();
Spatial model = app.getAssetManager().loadModel(modelName);
model.scale(asset.getSize());
model.rotate((float) Math.toRadians(0), 0, (float) Math.toRadians(rot));
model.setLocalTranslation(pos);
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat);
node.attachChild(model);
return model;
}
private static Vector3f gridToWorld(int x, int y) {
return new Vector3f(GRID_SIZE * x, GRID_SIZE * y, GRID_ELEVATION);
}
private Spatial displayAsset(AssetOnMap assetOnMap) {
int x = assetOnMap.x();
int y = assetOnMap.y();
return createModel(assetOnMap.asset(), gridToWorld(x, y), assetOnMap.rot());
}
private <T extends AbstractControl> T displayAndControl(AssetOnMap assetOnMap, T control) {
Spatial spatial = displayAsset(assetOnMap);
spatial.addControl(control);
return control;
}
private void movePieceToNode(PieceControl pieceControl, NodeControl nodeControl){
pieceControl.setLocation(nodeControl.getLocation());
}
private void addHomeNode(Map<Color, List<NodeControl>> map, Color color, AssetOnMap assetOnMap){
List<NodeControl> homeNodes = addItemToMapList(map, color, displayAndControl(assetOnMap, new NodeControl()));
assert(homeNodes.size() <= 4) : "BoardView: too many homeNodes for " + color;
}
private float getRotationMove(Vector3f prev, Vector3f next) {
Vector3f direction = next.subtract(prev).normalizeLocal();
//I had to reverse dir.y, because then it worked.
return (float) Math.toDegrees(Math.atan2(direction.x, -direction.y));
}
private void movePiece_rek(UUID uuid, int curIndex, int moveIndex){
if (curIndex == moveIndex) return;
curIndex = (curIndex + 1) % 40;
PieceControl pieceControl = pieces.get(uuid);
NodeControl nodeControl = infield.get(curIndex);
pieceControl.setRotation(getRotationMove(pieceControl.getLocation(),nodeControl.getLocation()));
movePieceToNode(pieceControl, nodeControl);
movePiece_rek(uuid, curIndex, moveIndex);
}
private <T, E> List<T> addItemToMapList(Map<E,List<T>> map, E key, T item){
List<T> list = map.getOrDefault(key, new ArrayList<>());
list.add(item);
map.put(key, list);
return list;
}
private <T, E> List<T> removeItemFromMapList(Map<E,List<T>> map, E key, T item){
List<T> list = map.getOrDefault(key, new ArrayList<>());
list.remove(item);
map.put(key, list);
return list;
}
//public methods****************************************************************************************************
public void addPlayer(Color color, List<UUID> uuid) {
List<AssetOnMap> playerAssets = colorAssetsMap.get(color);
assert (playerAssets != null) : "Assets for Player color are not defined";
assert (uuid.size() == playerAssets.size()) : "UUID array and playerAssets are not the same size";
List<NodeControl> waitNodes = waitingNodesMap.get(color);
assert(waitNodes.size() == playerAssets.size()) : "BoardHandler: waitNodes size does not match playerAssets size";
for (int i = 0; i < playerAssets.size(); i++){
AssetOnMap assetOnMap = playerAssets.get(i);
PieceControl pieceControl = displayAndControl(assetOnMap, new PieceControl(assetOnMap.rot(), app.getAssetManager(), app.getRootNode()));
movePieceToNode(pieceControl, waitNodes.get(i));
pieces.put(uuid.get(i), pieceControl);
pieceColor.put(uuid.get(i), color);
addItemToMapList(waitingPiecesMap, color, pieceControl);
}
}
public void moveHomePiece(UUID uuid, int index){
Color color = pieceColor.get(uuid);
assert(color != null) : "BoardHandler: uuid is not mapped to a color";
List<NodeControl> homeNodes = homeNodesMap.get(color);
assert(homeNodesMap.size() == 4) : "BoardView: HomeNodes for " + color + " are not defined";
PieceControl pieceControl = pieces.get(uuid);
NodeControl nodeControl = homeNodes.get(index);
movePieceToNode(pieceControl, nodeControl);
//rotate piece in direction of homeNodes
NodeControl firstHomeNode = homeNodes.get(0);
NodeControl lastHomeNode = homeNodes.get(homeNodes.size()-1);
pieceControl.setRotation(getRotationMove(firstHomeNode.getLocation(), lastHomeNode.getLocation()));
}
public void movePieceStart(UUID uuid, int nodeIndex){
Color color = pieceColor.get(uuid);
assert(color != null) : "BoardHandler: uuid is not mapped to a color";
PieceControl pieceControl = pieces.get(uuid);
movePieceToNode(pieceControl, infield.get(nodeIndex));
removeItemFromMapList(waitingPiecesMap, color, pieceControl);
}
public void movePiece(UUID uuid, int curIndex, int moveIndex){
movePiece_rek(uuid, curIndex, moveIndex);
}
public void throwPiece(UUID uuid){
Color color = pieceColor.get(uuid);
assert(color != null) : "BoardHandler: uuid is not mapped to a color";
PieceControl pieceControl = pieces.get(uuid);
List<NodeControl> waitNodes = waitingNodesMap.get(color);
List<PieceControl> waitPieces = waitingPiecesMap.get(color);
movePieceToNode(pieceControl, waitNodes.get(waitPieces.size()));
pieceControl.rotateInit();
}
public void shieldPiece(UUID uuid){
pieces.get(uuid).activateShield();
}
public void unshieldPiece(UUID uuid){
pieces.get(uuid).deactivateShield();
}
public void suppressShield(UUID uuid){
pieces.get(uuid).suppressShield();
}
public void swapPieces(UUID piece1, UUID piece2){
PieceControl piece1_control = pieces.get(piece1);
PieceControl piece2_control = pieces.get(piece2);
assert(piece1_control != null) : "BoardHandler: swap: piece1 UUID is not valid";
assert(piece2_control != null) : "BoardHandler: swap: piece2 UUID is not valid";
float rot1 = piece1_control.getRotation();
float rot2 = piece2_control.getRotation();
piece1_control.setRotation(rot2);
piece2_control.setRotation(rot1);
Vector3f pos1 = piece1_control.getLocation();
Vector3f pos2 = piece2_control.getLocation();
piece1_control.setLocation(pos2);
piece2_control.setLocation(pos1);
}
public void test(UUID uuid){
System.out.println((float) Math.toDegrees(Math.atan2(1,0)));
System.out.println((float) Math.toDegrees(Math.atan2(-1,0)));
System.out.println((float) Math.toDegrees(Math.atan2(0,1)));
System.out.println((float) Math.toDegrees(Math.atan2(0,-1)));
System.out.println(pieces.get(uuid).getRotation());
pieces.get(uuid).setRotation(-90);
System.out.println(pieces.get(uuid).getRotation());
}
}

View File

@@ -0,0 +1,49 @@
package pp.mdga.client.board;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import pp.mdga.client.MdgaApp;
public class CameraHandler {
MdgaApp app;
private DirectionalLight sun;
private AmbientLight ambient;
private static final int SHADOWMAP_SIZE = 1024 * 8;
public CameraHandler(MdgaApp app){
this.app = app;
sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(0.3f, 0, -1));
ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1));
}
public void init() {
app.getFlyByCamera().setEnabled(true);
int zoom = 15;
app.getCamera().setLocation(new Vector3f(-zoom, 0, zoom));
app.getCamera().lookAt(new Vector3f(0, 0, 0), new Vector3f(0, 0, 1));
DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(app.getAssetManager(), SHADOWMAP_SIZE, 4);
dlsr.setLight(sun);
app.getViewPort().addProcessor(dlsr);
app.getRootNode().addLight(sun);
app.getRootNode().addLight(ambient);
}
public void shutdown() {
app.getRootNode().removeLight(sun);
app.getRootNode().removeLight(ambient);
}
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client.Board;
package pp.mdga.client.board;
import java.io.BufferedReader;
import java.io.IOException;
@@ -70,6 +70,10 @@ private static BoardAsset getLoadedAsset(String assetName) {
case "node_home_yellow" -> BoardAsset.node_home_yellow;
case "node_home_black" -> BoardAsset.node_home_black;
case "node_home_green" -> BoardAsset.node_home_green;
case "node_wait_blue" -> BoardAsset.node_wait_blue;
case "node_wait_yellow" -> BoardAsset.node_wait_yellow;
case "node_wait_black" -> BoardAsset.node_wait_black;
case "node_wait_green" -> BoardAsset.node_wait_green;
case "world" -> BoardAsset.world;
case "jet" -> BoardAsset.jet;
case "big_tent" -> BoardAsset.bigTent;
@@ -77,6 +81,8 @@ private static BoardAsset getLoadedAsset(String assetName) {
case "radar" -> BoardAsset.radar;
case "ship" -> BoardAsset.ship;
case "tank" -> BoardAsset.tank;
case "tree_small" -> BoardAsset.tree_small;
case "tree_big" -> BoardAsset.tree_big;
default -> throw new IllegalStateException("Unexpected value: " + assetName);
};
}

View File

@@ -1,5 +1,6 @@
package pp.mdga.client.Board;
package pp.mdga.client.board;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
@@ -8,11 +9,14 @@ public class NodeControl extends AbstractControl {
@Override
protected void controlUpdate(float v) {
}
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
}
public Vector3f getLocation(){
return this.getSpatial().getLocalTranslation();
}
}

View File

@@ -0,0 +1,113 @@
package pp.mdga.client.board;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
public class PieceControl extends AbstractControl {
private float rotation;
private final float initRotation;
private AssetManager assetManager;
private Spatial shieldRing;
private Node rootNode;
private Material shield_mat;
private static final float SHIELD_SPEED = 1f;
private static final float SHIELD_TRANSPARENCY = 0.6f;
private static final ColorRGBA SHIELD_COLOR = new ColorRGBA(0, 0.9f, 1, SHIELD_TRANSPARENCY);
private static final ColorRGBA SHIELD_SUPPRESSED_COLOR = new ColorRGBA(1f, 0.5f, 0, SHIELD_TRANSPARENCY);
private static final float SHIELD_Z = 0f;
public PieceControl(float initRotation, AssetManager assetManager, Node rootNode){
super();
this.initRotation = initRotation;
this.assetManager = assetManager;
this.shieldRing = null;
this.rootNode = rootNode;
this.shield_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
this.shield_mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
}
public float getRotation() {
return (float) Math.toDegrees(this.spatial.getLocalRotation().toAngleAxis(new Vector3f(0,0,1)));
// return rotation;
}
public void setRotation(float rot){
Quaternion quaternion = new Quaternion();
quaternion.fromAngleAxis((float) Math.toRadians(rot), new Vector3f(0,0,1));
this.spatial.setLocalRotation(quaternion);
// this.getSpatial().rotate(0, 0, (float) Math.toRadians(rot));
}
public Vector3f getLocation(){
return this.getSpatial().getLocalTranslation();
}
@Override
protected void controlUpdate(float delta) {
if(shieldRing != null){
shieldRing.rotate(0, 0, delta * SHIELD_SPEED);
}
}
@Override
protected void controlRender(RenderManager renderManager, ViewPort viewPort) {
}
public void setLocation(Vector3f loc){
this.getSpatial().setLocalTranslation(loc);
}
@Override
public void setSpatial(Spatial spatial){
super.setSpatial(spatial);
if(spatial != null){
setRotation(this.initRotation);
}
}
public void rotateInit() {
// rotate(rotation - initRotation);
}
public void activateShield(){
shieldRing = assetManager.loadModel(BoardAsset.shield_ring.getModelPath());
shieldRing.scale(1f);
shieldRing.rotate((float) Math.toRadians(0), 0, (float) Math.toRadians(0));
shieldRing.setLocalTranslation(spatial.getLocalTranslation().add(new Vector3f(0,0,SHIELD_Z)));
shieldRing.setQueueBucket(RenderQueue.Bucket.Transparent); // Render in the transparent bucket
shield_mat.setColor("Color", SHIELD_COLOR);
shieldRing.setMaterial(shield_mat);
rootNode.attachChild(shieldRing);
}
public void deactivateShield(){
rootNode.detachChild(shieldRing);
shieldRing = null;
}
public void suppressShield(){
assert(shieldRing != null) : "PieceControl: shieldRing is not set";
shield_mat.setColor("Color", SHIELD_SUPPRESSED_COLOR);
}
}

View File

@@ -0,0 +1,5 @@
package pp.mdga.client.board;
class PileControl {
}

View File

@@ -0,0 +1,12 @@
package pp.mdga.client.board;
public enum Rotation {
UP,
RIGHT,
DOWN,
LEFT,
UP_LEFT,
UP_RIGHT,
DOWN_RIGHT,
DOWN_LEFT
}

View File

@@ -0,0 +1,82 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
import static com.jme3.math.FastMath.floor;
public abstract class Dialog {
protected final ColorRGBA COLOR_DEFAULT = ColorRGBA.Gray;
protected final ColorRGBA COLOR_HOVER = ColorRGBA.DarkGray;
protected Container container;
protected final MdgaApp app;
private final Node node;
protected final float vertical_step;
protected final float horitontal_step;
protected float fontSize = 35;
public Dialog(MdgaApp app, Node node) {
this.app = app;
this.node = node;
this.container = new Container();
this.horitontal_step = app.getCamera().getWidth() / 16;
this.vertical_step = app.getCamera().getHeight() / 9;
int val = (int) (32 * Math.min(app.getResolutionFactor() * 0.9f, 1));
fontSize = val;
}
public void show() {
node.attachChild(container);
}
public void hide () {
node.detachChild(container);
}
protected void createButton(String label, Runnable action, Vector3f size) {
Button button = new Button(label);
button.addClickCommands(source -> action.run());
button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
});
container.addChild(button);
}
}

View File

@@ -0,0 +1,88 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import pp.mdga.client.MdgaApp;
public class InputButtonDialog extends Dialog {
private TextField nameInput;
public InputButtonDialog(MdgaApp app, Node node) {
super(app, node);
QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
Texture texture = app.getAssetManager().loadTexture("mdga_logo.png");
QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
Panel imagePanel = new Panel();
imagePanel.setBackground(b);
container.addChild(imagePanel).setPreferredSize(new Vector3f(texture.getImage().getWidth() / 4, texture.getImage().getHeight() / 4, 0));
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
createTextField();
//abstandshalter
container.addChild(new Panel(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
}
@Override
public void show() {
super.show();
container.setLocalTranslation(
app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
}
@Override
public void hide() {
super.hide();
}
public void addButton(String label, Runnable action, Vector3f size) {
createButton(label, action, size);
}
private void createTextField() {
Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
Label nameLabel = new Label("Name:\t");
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
nameInput = new TextField("");
nameInput.setColor(ColorRGBA.Black);
nameInput.setTextHAlignment(HAlignment.Left);
nameInput.setFontSize(fontSize);
nameInput.setSingleLine(true);
QuadBackgroundComponent grayBackground = new QuadBackgroundComponent(ColorRGBA.DarkGray);
nameInput.setBackground(grayBackground);
subContainer.addChild(nameLabel);
subContainer.addChild(nameInput);
container.addChild(subContainer);
}
public String getName() {
return nameInput.getText();
}
}

View File

@@ -0,0 +1,32 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
public class LobbyButtonDialog extends Dialog {
private final int pos;
public LobbyButtonDialog(MdgaApp app, Node node, String label, Runnable action, int pos) {
super(app, node);
this.pos = pos;
createButton(label, action, new Vector3f(170 * app.getResolutionFactor(), 250 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = ((2 + (4 * pos)) * horitontal_step) - ((0.33333333f * pos) * container.getPreferredSize().x);
float y = 6 * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
}

View File

@@ -0,0 +1,15 @@
package pp.mdga.client.dialog;
import java.util.function.Consumer;
public class PercentRunnable {
private final Consumer<Float> action;
public PercentRunnable(Consumer<Float> action) {
this.action = action;
}
public void run(float percent) {
action.accept(percent);
}
}

View File

@@ -0,0 +1,78 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import pp.mdga.client.MdgaApp;
public class SettingsButtonDialog extends Dialog {
private IconComponent icon;
public SettingsButtonDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
icon = new IconComponent("zahnrad.png");
icon.setIconScale(0.1f * app.getResolutionFactor());
createButton(label, action, new Vector3f(60 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = (15.5f * horitontal_step) - container.getPreferredSize().x;
float y = 8.5f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
@Override
protected void createButton(String label, Runnable action, Vector3f size) {
Button button = new Button(label);
button.addClickCommands(source -> action.run());
button.setFontSize(fontSize);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setPreferredSize(size);
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
QuadBackgroundComponent background = new QuadBackgroundComponent(COLOR_DEFAULT);
background.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
button.setBackground(background);
button.setIcon(icon);
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOn, (source) -> {
QuadBackgroundComponent hoverBackground = new QuadBackgroundComponent(COLOR_HOVER);
hoverBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(hoverBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setIcon(icon);
});
button.addCommands(com.simsilica.lemur.Button.ButtonAction.HighlightOff, (source) -> {
QuadBackgroundComponent normalBackground = new QuadBackgroundComponent(COLOR_DEFAULT);
normalBackground.setMargin(5 * app.getResolutionFactor(), 5 * app.getResolutionFactor());
source.setBackground(normalBackground);
button.setHighlightColor(ColorRGBA.White);
button.setColor(ColorRGBA.Black);
button.setIcon(icon);
});
container.addChild(button);
}
}

View File

@@ -0,0 +1,103 @@
package pp.mdga.client.dialog;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.simsilica.lemur.*;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.event.CursorListener;
import com.simsilica.lemur.event.CursorMotionEvent;
import com.simsilica.lemur.event.MouseEventControl;
import pp.mdga.client.MdgaApp;
import com.simsilica.lemur.*;
import com.simsilica.lemur.style.*;
import java.util.HashMap;
public class SettingsDialog extends Dialog {
private TextField nameInput;
private HashMap<Slider, PercentRunnable> map = new HashMap<Slider, PercentRunnable>();
public SettingsDialog(MdgaApp app, Node node, String path) {
super(app, node);
QuadBackgroundComponent quad1 = new QuadBackgroundComponent(ColorRGBA.Gray);
quad1.setMargin(100 * app.getResolutionFactor(), 50 * app.getResolutionFactor());
container.setBackground(quad1);
Texture texture = app.getAssetManager().loadTexture(path);
QuadBackgroundComponent b = new QuadBackgroundComponent(texture);
Panel imagePanel = new Panel();
imagePanel.setBackground(b);
container.addChild(imagePanel).setPreferredSize(new Vector3f((texture.getImage().getWidth() / 2) * app.getResolutionFactor(), (texture.getImage().getHeight() / 2) * app.getResolutionFactor(), 0));
//abstandshalter
container.addChild(new Panel(80 * app.getResolutionFactor(), 50 * app.getResolutionFactor(), ColorRGBA.Gray));
}
@Override
public void show() {
super.show();
container.setLocalTranslation(
app.getCamera().getWidth() / 2 - container.getPreferredSize().x / 2,
app.getCamera().getHeight() / 2 + container.getPreferredSize().y / 2,
0
);
}
@Override
public void hide() {
super.hide();
}
public void addButton(String label, Runnable action, Vector3f size) {
createButton(label, action, size);
}
public void addSlider(String label, PercentRunnable action, Vector3f size, int start) {
Container subContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y));
Slider slider = new Slider("slider");
QuadBackgroundComponent background = new QuadBackgroundComponent(ColorRGBA.DarkGray);
slider.setBackground(background);
slider.setPreferredSize(size);
slider.setModel(new DefaultRangedValueModel(0, 10, start));
slider.setPreferredSize(new Vector3f(150 * app.getResolutionFactor(), 30 * app.getResolutionFactor(), 0));
slider.getDecrementButton().setText(" - ");
slider.getIncrementButton().setText(" + ");
slider.getDecrementButton().setFontSize(25 * app.getResolutionFactor());
slider.getIncrementButton().setFontSize(25 * app.getResolutionFactor());
Label nameLabel = new Label(label);
nameLabel.setFontSize(fontSize);
nameLabel.setColor(ColorRGBA.Black);
nameLabel.setPreferredSize(new Vector3f(150 * app.getResolutionFactor(), 10 * app.getResolutionFactor(), 0));
subContainer.addChild(nameLabel);
subContainer.addChild(slider);
container.addChild(subContainer);
map.put(slider, action);
//abstandshalter
container.addChild(new Panel(20 * app.getResolutionFactor(), 10 * app.getResolutionFactor(), ColorRGBA.Gray));
}
public void update() {
map.forEach((slider, runnable) -> {
float val = (float) slider.getModel().getPercent();
runnable.run(val);
});
}
}

View File

@@ -0,0 +1,28 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
public class SingleButtonLeftDialog extends Dialog {
public SingleButtonLeftDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
createButton(label, action, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = 2 * horitontal_step;
float y = 1.8f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
}

View File

@@ -0,0 +1,28 @@
package pp.mdga.client.dialog;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import pp.mdga.client.MdgaApp;
public class SingleButtonRightDialog extends Dialog {
public SingleButtonRightDialog(MdgaApp app, Node node, String label, Runnable action) {
super(app, node);
createButton(label, action, new Vector3f(170 * app.getResolutionFactor(), 60 * app.getResolutionFactor(), 0));
}
@Override
public void show() {
super.show();
float x = (14 * horitontal_step) - container.getPreferredSize().x;
float y = 1.8f * vertical_step;
container.setLocalTranslation(x, y, 0);
}
@Override
public void hide() {
super.hide();
}
}

View File

@@ -0,0 +1,5 @@
package pp.mdga.client.gui;
public class GuiView {
}

View File

@@ -0,0 +1,98 @@
package pp.mdga.client.view;
import com.jme3.scene.Geometry;
import pp.mdga.client.dialog.SingleButtonLeftDialog;
import pp.mdga.client.dialog.SingleButtonRightDialog;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
public class CeremonyView extends MdgaView {
private enum SubState {
AWARD_CEREMONY,
STATISTICS,
}
private SubState state;
private SingleButtonRightDialog continueButton;
private SingleButtonLeftDialog backButton;
private Geometry background;
public CeremonyView(MdgaApp app) {
super(app);
continueButton = new SingleButtonRightDialog(app, node, "Weiter", () -> forward());
backButton = new SingleButtonLeftDialog(app, node, "Zurück", () -> back());
}
@Override
public void onEnter() {
enterSub(SubState.AWARD_CEREMONY);
}
@Override
public void onLeave() {
continueButton.hide();
backButton.hide();
}
private void awardCeremony() {
background = createBackground("b1.png");
node.attachChild(background);
continueButton.show();
backButton.hide();
}
private void statistics() {
background = createBackground("b2.png");
node.attachChild(background);
continueButton.show();
backButton.show();
}
private void enterSub(SubState state) {
this.state = state;
if(null != background) {
node.detachChild(background);
}
backButton.hide();
continueButton.hide();
switch (state) {
case AWARD_CEREMONY:
awardCeremony();
break;
case STATISTICS:
statistics();
break;
}
}
private void forward() {
switch (state) {
case AWARD_CEREMONY:
enterSub(SubState.STATISTICS);
break;
case STATISTICS:
app.enter(MdgaState.MAIN);
break;
}
}
private void back() {
switch (state) {
case AWARD_CEREMONY:
//nothing
break;
case STATISTICS:
enterSub(SubState.AWARD_CEREMONY);
break;
}
}
}

View File

@@ -0,0 +1,39 @@
package pp.mdga.client.view;
import pp.mdga.client.board.BoardHandler;
import pp.mdga.client.board.CameraHandler;
import pp.mdga.client.dialog.SingleButtonRightDialog;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
public class GameView extends MdgaView {
private BoardHandler boardHandler;
private CameraHandler camera;
private SingleButtonRightDialog continueButton;
public GameView(MdgaApp app) {
super(app);
this.boardHandler = new BoardHandler(app);
this.camera = new CameraHandler(app);
continueButton = new SingleButtonRightDialog(app, node, "Weiter", () -> app.enter(MdgaState.CEREMONY));
}
@Override
public void onEnter() {
boardHandler.init();
camera.init();
continueButton.show();
}
@Override
public void onLeave() {
continueButton.hide();
camera.shutdown();
boardHandler.shutdown();
}
}

View File

@@ -0,0 +1,57 @@
package pp.mdga.client.view;
import com.jme3.scene.Geometry;
import pp.mdga.client.dialog.LobbyButtonDialog;
import pp.mdga.client.dialog.SingleButtonLeftDialog;
import pp.mdga.client.dialog.SingleButtonRightDialog;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
import java.util.ArrayList;
public class LobbyView extends MdgaView {
private Geometry background;
private SingleButtonRightDialog readyButton;
private SingleButtonLeftDialog leaveButton;
private ArrayList<LobbyButtonDialog> lobbyButtons = new ArrayList<>();
public LobbyView(MdgaApp app) {
super(app);
background = createBackground("lobby.png");
node.attachChild(background);
readyButton = new SingleButtonRightDialog(app, node, "Fertig", () -> app.enter(MdgaState.GAME));
leaveButton = new SingleButtonLeftDialog(app, node, "Verlassen", () -> app.enter(MdgaState.MAIN));
lobbyButtons.add(new LobbyButtonDialog(app, node, "CIR", () -> System.out.println("cir"), 0));
lobbyButtons.add(new LobbyButtonDialog(app, node, "LUFTWAFFE", () -> System.out.println("lw"), 1));
lobbyButtons.add(new LobbyButtonDialog(app, node, "HEER", () -> System.out.println("heer"), 2));
lobbyButtons.add(new LobbyButtonDialog(app, node, "MARINE", () -> System.out.println("marine"), 3));
}
@Override
public void onEnter() {
readyButton.show();
leaveButton.show();
for (LobbyButtonDialog b : lobbyButtons) {
b.show();
}
}
@Override
public void onLeave() {
for (LobbyButtonDialog b : lobbyButtons) {
b.hide();
}
readyButton.hide();
leaveButton.hide();
}
}

View File

@@ -0,0 +1,39 @@
package pp.mdga.client.view;
import com.jme3.scene.Geometry;
import pp.mdga.client.dialog.InputButtonDialog;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
import com.jme3.math.Vector3f;
public class MainView extends MdgaView {
private Geometry background;
private InputButtonDialog dialog;
public MainView(MdgaApp app) {
super(app);
background = createBackground("powercards.png");
node.attachChild(background);
Vector3f size = new Vector3f(280, 60, 0);
dialog = new InputButtonDialog(app, node);
dialog.addButton("Spiel beitreten", () -> app.enter(MdgaState.LOBBY), size);
dialog.addButton("Spiel hosten", () -> app.enter(MdgaState.LOBBY), size);
dialog.addButton("Einstellungen", () -> enterSettings(false), size);
dialog.addButton("Spiel beenden", () -> app.stop(), size);
}
@Override
public void onEnter() {
dialog.show();
}
@Override
public void onLeave() {
dialog.hide();
}
}

View File

@@ -0,0 +1,195 @@
package pp.mdga.client.view;
import com.jme3.asset.TextureKey;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import pp.mdga.client.dialog.PercentRunnable;
import pp.mdga.client.dialog.SettingsButtonDialog;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.dialog.SettingsDialog;
public abstract class MdgaView {
protected MdgaApp app;
protected Node node;
int depth = 0;
boolean isVideo = false;
boolean isAudio = false;
private Node settingsNode;
private Node audioNode;
private Node videoNode;
private SettingsButtonDialog settingsButton;
private Geometry settingsBackground;
private Geometry audioBackground;
private Geometry videoBackground;
private SettingsDialog settings;
private SettingsDialog audio;
private SettingsDialog video;
public MdgaView(MdgaApp app) {
this.app = app;
this.node = new Node();
this.settingsNode = new Node();
this.audioNode = new Node();
this.videoNode = new Node();
this.settingsButton = new SettingsButtonDialog(app, node, "", () -> enterSettings(false));
this.settingsBackground = createBackground("background/zahnräder.png");
settingsNode.attachChild(settingsBackground);
this.audioBackground = createBackground("background/lautsprecher.png");
audioNode.attachChild(audioBackground);
this.videoBackground = createBackground("background/monitors.png");
videoNode.attachChild(videoBackground);
Vector3f size = new Vector3f(280, 60, 0);
this.settings = new SettingsDialog(app, settingsNode, "zahnrad.png");
this.settings.addButton("Video", () -> enterVideo(), size);
this.settings.addButton("Audio", () -> enterAudio(), size);
this.settings.addButton("Zurück", () -> leaveSettings(false), size);
this.audio = new SettingsDialog(app, audioNode, "audio_icon.png");
this.audio.addSlider("Lautstärke", new PercentRunnable(app.getAcousticHandler()::setMainVolume), size, 5);
this.audio.addSlider("Musik", new PercentRunnable(app.getAcousticHandler()::setMusicVolume), size, 10);
this.audio.addSlider("Sound", new PercentRunnable(app.getAcousticHandler()::setSoundVolume), size, 10);
this.audio.addButton("Zurück", () -> leaveAudio(), size);
this.video = new SettingsDialog(app, videoNode, "monitor.png");
this.video.addButton("A", () -> System.out.println("A"), size);
this.video.addButton("B", () -> System.out.println("B"), size);
this.video.addButton("Zurück", () -> leaveVideo(), size);
}
public void enter() {
app.getGuiNode().attachChild(node);
settingsButton.show();
onEnter();
}
public void leave() {
onLeave();
settingsButton.hide();
app.getGuiNode().detachChild(node);
}
public void update() {
audio.update();
}
protected abstract void onEnter();
protected abstract void onLeave();
protected Geometry createBackground(String texturePath) {
TextureKey key = new TextureKey(texturePath, true);
Texture backgroundTexture = app.getAssetManager().loadTexture(key);
Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight());
Geometry background = new Geometry("Background", quad);
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", backgroundTexture);
background.setMaterial(mat);
background.setLocalTranslation(0, 0, -1);
return background;
}
protected void enterSettings(boolean soft) {
leave();
app.getGuiNode().attachChild(settingsNode);
if(!soft) {
depth++;
}
settings.show();
}
protected void leaveSettings(boolean soft) {
settings.hide();
app.getGuiNode().detachChild(settingsNode);
if(!soft) {
enter();
depth--;
}
}
protected void enterAudio() {
leaveSettings(true);
depth++;
isAudio = true;
app.getGuiNode().attachChild(audioNode);
audio.show();
}
protected void leaveAudio() {
audio.hide();
app.getGuiNode().detachChild(audioNode);
isAudio = false;
depth--;
enterSettings(true);
}
protected void enterVideo() {
leaveSettings(true);
app.getGuiNode().attachChild(videoNode);
depth++;
isVideo = true;
video.show();
}
protected void leaveVideo() {
video.hide();
app.getGuiNode().detachChild(videoNode);
depth--;
isVideo = false;
enterSettings(true);
}
public void pressEscape() {
if(depth == 0) {
enterSettings(false);
} else if(depth == 1) {
leaveSettings(false);
}
else if (depth == 2){
if(isVideo) {
leaveVideo();
}
if(isAudio) {
leaveAudio();
}
} else {
throw new RuntimeException();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -1,65 +1,68 @@
world 0,0 0
world 0,0 90
#tree_small 1,1 0
#tree_big 0,0 0
#Marine Pos
marine 4,-5 180
marine 4,-4 180
marine 5,-4 180
marine 5,-5 180
marine 4,-5 -90
marine 4,-4 -90
marine 5,-4 -90
marine 5,-5 -90
#Blue (Marine) Home Node
node_home_blue 4,-5 0
node_home_blue 4,-4 0
node_home_blue 5,-4 0
node_home_blue 5,-5 0
#Blue (Marine) wait Node
node_wait_blue 4,-5 0
node_wait_blue 4,-4 0
node_wait_blue 5,-4 0
node_wait_blue 5,-5 0
#Lw Pos
lw -5,4 0
lw -4,4 0
lw -4,5 0
lw -5,5 0
lw -5,4 90
lw -4,4 90
lw -4,5 90
lw -5,5 90
#Black (Lw) Home Node
node_home_black -5,4 0
node_home_black -4,4 0
node_home_black -4,5 0
node_home_black -5,5 0
#Black (Lw) wait Node
node_wait_black -5,4 0
node_wait_black -4,4 0
node_wait_black -4,5 0
node_wait_black -5,5 0
#Heer Pos
heer -4,-5 90
heer -4,-4 90
heer -5,-4 90
heer -5,-5 90
heer -4,-5 180
heer -4,-4 180
heer -5,-4 180
heer -5,-5 180
#Green (Heer) Home Node
node_home_green -4,-5 0
node_home_green -4,-4 0
node_home_green -5,-4 0
node_home_green -5,-5 0
#Green (Heer) Wait Node
node_wait_green -4,-5 0
node_wait_green -4,-4 0
node_wait_green -5,-4 0
node_wait_green -5,-5 0
#CIR Pos
cir 4,5 -90
cir 4,4 -90
cir 5,4 -90
cir 5,5 -90
cir 4,5 0
cir 4,4 0
cir 5,4 0
cir 5,5 0
#Assets
jet -10,-1 -45
ship 11,0 79
big_tent -9,-7 40
big_tent 7,-10 135
small_tent -9,7 -45
small_tent -10,5 -30
radar 0,10 -110
small_tent 6,8 100
small_tent 8,7 70
tank -1,-10 45
jet -10,-1 45
ship 11,0 169
big_tent -9,-7 130
big_tent 7,-10 225
small_tent -9,7 45
small_tent -10,5 60
radar 0,10 -20
small_tent 6,8 190
small_tent 8,7 160
tank -1,-10 135
#Yellow (CIR) Home Node
node_home_yellow 4,5 0
node_home_yellow 4,4 0
node_home_yellow 5,4 0
node_home_yellow 5,5 0
#Yellow (CIR) wait Node
node_wait_yellow 4,5 0
node_wait_yellow 4,4 0
node_wait_yellow 5,4 0
node_wait_yellow 5,5 0
#Nodes für Map
node_start -5,1 0
@@ -105,22 +108,22 @@ node -5,0 0
#Node Home
node_home_green 0,-1 0
node_home_green 0,-2 0
node_home_green 0,-3 0
node_home_green 0,-4 0
node_home_yellow 0,1 0
node_home_yellow 0,2 0
node_home_yellow 0,3 0
node_home_yellow 0,4 0
node_home_blue 1,0 0
node_home_blue 2,0 0
node_home_blue 3,0 0
node_home_blue 4,0 0
node_home_black -1,0 0
node_home_black -2,0 0
node_home_black -3,0 0
node_home_black -4,0 0
node_home_black -3,0 0
node_home_black -2,0 0
node_home_black -1,0 0
node_home_green 0,-4 0
node_home_green 0,-3 0
node_home_green 0,-2 0
node_home_green 0,-1 0
node_home_yellow 0,4 0
node_home_yellow 0,3 0
node_home_yellow 0,2 0
node_home_yellow 0,1 0
node_home_blue 4,0 0
node_home_blue 3,0 0
node_home_blue 2,0 0
node_home_blue 1,0 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -0,0 +1,616 @@
# Blender 3.6.5
# www.blender.org
o shield
v 0.329363 -0.615745 1.151866
v -0.000000 -0.615745 0.415793
v -0.000000 -0.615745 1.151866
v 0.329363 -0.615745 1.092511
v -0.000000 -0.615745 0.415793
v 0.326010 -0.615745 0.996204
v 0.316022 -0.615745 0.901858
v 0.299600 -0.615745 0.811392
v 0.277080 -0.615745 0.726650
v 0.248920 -0.615745 0.649355
v 0.215692 -0.615745 0.581082
v 0.178074 -0.615745 0.523220
v 0.136832 -0.615745 0.476947
v 0.092804 -0.615745 0.443205
v 0.046887 -0.615745 0.422681
v -0.329363 -0.615745 1.151866
v -0.329363 -0.615745 1.092511
v -0.326010 -0.615745 0.996204
v -0.316022 -0.615745 0.901858
v -0.299600 -0.615745 0.811392
v -0.277080 -0.615745 0.726650
v -0.248920 -0.615745 0.649355
v -0.215692 -0.615745 0.581082
v -0.178075 -0.615745 0.523220
v -0.136832 -0.615745 0.476947
v -0.092804 -0.615745 0.443205
v -0.046887 -0.615745 0.422681
v 0.329363 -0.590929 1.151866
v -0.000000 -0.590929 1.151866
v -0.000000 -0.590929 0.415793
v -0.000000 -0.590929 0.415793
v 0.046887 -0.590929 0.422681
v 0.092804 -0.590929 0.443205
v 0.136832 -0.590929 0.476947
v 0.178074 -0.590929 0.523220
v 0.215692 -0.590929 0.581082
v 0.248920 -0.590929 0.649355
v 0.277080 -0.590929 0.726650
v 0.299600 -0.590929 0.811392
v 0.316022 -0.590929 0.901858
v 0.326010 -0.590929 0.996204
v 0.329363 -0.590929 1.092511
v -0.329363 -0.590929 1.151866
v -0.046887 -0.590929 0.422681
v -0.092804 -0.590929 0.443205
v -0.136832 -0.590929 0.476947
v -0.178075 -0.590929 0.523220
v -0.215692 -0.590929 0.581082
v -0.248920 -0.590929 0.649355
v -0.277080 -0.590929 0.726650
v -0.299600 -0.590929 0.811392
v -0.316022 -0.590929 0.901858
v -0.326010 -0.590929 0.996204
v -0.329363 -0.590929 1.092511
v -0.000000 0.740870 0.678108
v -0.000000 0.740870 1.005550
v 0.144537 0.726635 0.678108
v 0.144537 0.726635 1.005550
v 0.283519 0.684475 0.678108
v 0.283519 0.684475 1.005550
v 0.411605 0.616011 0.678108
v 0.411605 0.616011 1.005550
v 0.523874 0.523875 0.678108
v 0.523874 0.523874 1.005550
v 0.616011 0.411606 0.678108
v 0.616011 0.411606 1.005550
v 0.684475 0.283519 0.678108
v 0.684475 0.283519 1.005550
v 0.726635 0.144537 0.678108
v 0.726635 0.144537 1.005550
v 0.740870 0.000000 0.678108
v 0.740870 0.000000 1.005550
v 0.726635 -0.144537 0.678108
v 0.726635 -0.144537 1.005550
v 0.684475 -0.283519 0.678108
v 0.684475 -0.283519 1.005550
v 0.616011 -0.411605 0.678108
v 0.616011 -0.411605 1.005550
v 0.523874 -0.523874 0.678108
v 0.523874 -0.523874 1.005550
v 0.411605 -0.616011 0.678108
v 0.411605 -0.616011 1.005550
v -0.411606 -0.616011 0.678108
v -0.411606 -0.616011 1.005550
v -0.523875 -0.523874 0.678108
v -0.523875 -0.523875 1.005550
v -0.616011 -0.411606 0.678108
v -0.616011 -0.411606 1.005550
v -0.684475 -0.283519 0.678108
v -0.684475 -0.283519 1.005550
v -0.726635 -0.144537 0.678108
v -0.726635 -0.144537 1.005550
v -0.740870 -0.000000 0.678108
v -0.740870 -0.000000 1.005550
v -0.726635 0.144537 0.678108
v -0.726635 0.144537 1.005550
v -0.684475 0.283519 0.678108
v -0.684475 0.283519 1.005550
v -0.616011 0.411606 0.678108
v -0.616011 0.411606 1.005550
v -0.523875 0.523874 0.678108
v -0.523875 0.523874 1.005550
v -0.411606 0.616011 0.678108
v -0.411606 0.616011 1.005550
v -0.283519 0.684475 0.678108
v -0.283519 0.684475 1.005550
v -0.144537 0.726635 0.678108
v -0.144537 0.726635 1.005550
v -0.142275 0.717330 1.005550
v -0.142275 0.717330 0.678108
v -0.279082 0.675829 1.005550
v -0.279082 0.675829 0.678108
v -0.405165 0.608437 1.005550
v -0.405165 0.608437 0.678108
v -0.515677 0.517742 1.005550
v -0.515677 0.517742 0.678108
v -0.606372 0.407230 1.005550
v -0.606372 0.407230 0.678108
v -0.673764 0.281147 1.005550
v -0.673764 0.281147 0.678108
v -0.715265 0.144340 1.005550
v -0.715265 0.144340 0.678108
v -0.729277 0.002065 1.005550
v -0.729277 0.002065 0.678108
v -0.715265 -0.140210 1.005550
v -0.715265 -0.140210 0.678108
v -0.673764 -0.277017 1.005550
v -0.673764 -0.277017 0.678108
v -0.606372 -0.403100 1.005550
v -0.606372 -0.403100 0.678108
v -0.515677 -0.513612 1.005550
v -0.515677 -0.513612 0.678108
v -0.405165 -0.604307 0.678108
v -0.405165 -0.604307 1.005550
v 0.405165 -0.604307 1.005550
v 0.405165 -0.604307 0.678108
v 0.515677 -0.513612 1.005550
v 0.515677 -0.513612 0.678108
v 0.606372 -0.403100 1.005550
v 0.606372 -0.403100 0.678108
v 0.673764 -0.277017 1.005550
v 0.673764 -0.277017 0.678108
v 0.715264 -0.140210 1.005550
v 0.715264 -0.140210 0.678108
v 0.729277 0.002065 1.005550
v 0.729277 0.002065 0.678108
v 0.715264 0.144340 1.005550
v 0.715264 0.144340 0.678108
v 0.673764 0.281147 1.005550
v 0.673764 0.281147 0.678108
v 0.606372 0.407230 1.005550
v 0.606372 0.407230 0.678108
v 0.515677 0.517742 1.005550
v 0.515677 0.517742 0.678108
v 0.405165 0.608437 1.005550
v 0.405165 0.608437 0.678108
v 0.279082 0.675829 1.005550
v 0.279082 0.675829 0.678108
v -0.000000 0.731342 1.005550
v 0.142275 0.717330 1.005550
v 0.142275 0.717330 0.678108
v -0.000000 0.731342 0.678108
vn -0.0000 -0.0000 1.0000
vn -0.9839 -0.0000 0.1786
vn 0.9994 -0.0000 0.0348
vn -0.4081 -0.0000 0.9130
vn 0.7465 -0.0000 0.6654
vn -0.9944 -0.0000 0.1053
vn 1.0000 -0.0000 -0.0000
vn -0.6083 -0.0000 0.7937
vn 0.8384 -0.0000 0.5451
vn -0.9994 -0.0000 0.0348
vn -0.7465 -0.0000 0.6654
vn 0.8992 -0.0000 0.4376
vn -1.0000 -0.0000 -0.0000
vn -0.8384 -0.0000 0.5451
vn 0.9396 -0.0000 0.3423
vn -0.0000 -0.0000 -1.0000
vn -0.8992 -0.0000 0.4376
vn 0.9665 -0.0000 0.2568
vn 0.1453 -0.0000 0.9894
vn -0.9396 -0.0000 0.3423
vn 0.9839 -0.0000 0.1786
vn 0.4081 -0.0000 0.9130
vn -0.9665 -0.0000 0.2568
vn 0.9944 -0.0000 0.1053
vn -0.1453 -0.0000 0.9894
vn 0.6083 -0.0000 0.7937
vn 0.0980 0.9952 -0.0000
vn 0.2903 0.9569 -0.0000
vn 0.4714 0.8819 -0.0000
vn 0.6344 0.7730 -0.0000
vn 0.7730 0.6344 -0.0000
vn 0.8819 0.4714 -0.0000
vn 0.9569 0.2903 -0.0000
vn 0.9952 0.0980 -0.0000
vn 0.9952 -0.0980 -0.0000
vn 0.9569 -0.2903 -0.0000
vn 0.8819 -0.4714 -0.0000
vn 0.7730 -0.6344 -0.0000
vn 0.6344 -0.7730 -0.0000
vn -0.6344 -0.7730 -0.0000
vn -0.7730 -0.6344 -0.0000
vn -0.8819 -0.4714 -0.0000
vn -0.9569 -0.2903 -0.0000
vn -0.9952 -0.0980 -0.0000
vn -0.9952 0.0980 -0.0000
vn -0.9569 0.2903 -0.0000
vn -0.8819 0.4714 -0.0000
vn -0.7730 0.6344 -0.0000
vn -0.6344 0.7730 -0.0000
vn -0.4714 0.8819 -0.0000
vn -0.2903 0.9569 -0.0000
vn -0.0980 0.9952 -0.0000
vn -0.8761 -0.4821 -0.0000
vn 0.4714 -0.8819 -0.0000
vn -0.4714 -0.8819 -0.0000
vn 0.8761 -0.4821 -0.0000
vn -0.2903 -0.9569 -0.0000
vn -0.0980 -0.9952 -0.0000
vn 0.0980 -0.9952 -0.0000
vn 0.2903 -0.9569 -0.0000
vn -0.0000 1.0000 -0.0000
vn -0.0000 -1.0000 -0.0000
vn -0.4081 -0.0000 0.9129
vn 0.4081 -0.0000 0.9129
vt 0.500025 0.000000
vt 0.500000 0.000000
vt 0.500000 1.000000
vt 0.571179 0.009358
vt 0.979748 0.660349
vt 0.954818 0.537446
vt 0.994911 0.788524
vt 1.000000 0.919363
vt 0.640884 0.037241
vt 0.707722 0.083081
vt 0.770332 0.145946
vt 1.000000 1.000000
vt 0.827439 0.224555
vt 0.877881 0.317308
vt 0.920631 0.422318
vt 0.968750 0.500000
vt 1.000000 0.500000
vt 0.968750 1.000000
vt 0.937500 0.500000
vt 0.937500 1.000000
vt 0.906250 0.500000
vt 0.906250 1.000000
vt 0.875000 0.500000
vt 0.875000 1.000000
vt 0.843750 0.500000
vt 0.843750 1.000000
vt 0.812500 0.500000
vt 0.781250 1.000000
vt 0.781250 0.500000
vt 0.750000 1.000000
vt 0.750000 0.500000
vt 0.718750 0.500000
vt 0.687500 1.000000
vt 0.687500 0.500000
vt 0.656250 0.500000
vt 0.656250 1.000000
vt 0.625000 0.500000
vt 0.625000 1.000000
vt 0.593750 0.500000
vt 0.406250 0.500000
vt 0.375000 1.000000
vt 0.375000 0.500000
vt 0.343750 1.000000
vt 0.343750 0.500000
vt 0.312500 0.500000
vt 0.312500 1.000000
vt 0.281250 0.500000
vt 0.250000 1.000000
vt 0.250000 0.500000
vt 0.218750 0.500000
vt 0.218750 1.000000
vt 0.187500 0.500000
vt 0.187500 1.000000
vt 0.156250 0.500000
vt 0.125000 1.000000
vt 0.125000 0.500000
vt 0.093750 0.500000
vt 0.093750 1.000000
vt 0.062500 0.500000
vt 0.000000 1.000000
vt 0.031250 1.000000
vt 0.062500 1.000000
vt 0.031250 0.500000
vt 0.000000 0.500000
vt 0.281250 1.000000
vt 0.593750 1.000000
vt 0.156250 1.000000
vt 0.718750 1.000000
vt 0.812500 1.000000
vt 0.406250 1.000000
s 0
f 5/1/1 2/2/1 3/3/1
f 2/2/1 5/1/1 27/4/1
f 30/2/1 31/1/1 32/4/1
f 31/1/1 30/2/1 29/3/1
f 7/5/2 39/6/2 8/6/2
f 18/7/3 54/8/3 17/8/3
f 15/4/4 33/9/4 32/4/4
f 25/10/5 47/11/5 24/11/5
f 6/7/6 40/5/6 7/5/6
f 17/8/7 43/12/7 16/12/7
f 14/9/8 34/10/8 33/9/8
f 24/11/9 48/13/9 23/13/9
f 4/8/10 41/7/10 6/7/10
f 12/11/11 34/10/11 13/10/11
f 23/13/12 49/14/12 22/14/12
f 1/12/13 42/8/13 4/8/13
f 11/13/14 35/11/14 12/11/14
f 22/14/15 50/15/15 21/15/15
f 3/3/16 28/12/16 1/12/16
f 16/12/16 29/3/16 3/3/16
f 10/14/17 36/13/17 11/13/17
f 21/15/18 51/6/18 20/6/18
f 5/1/19 44/4/19 27/4/19
f 9/15/20 37/14/20 10/14/20
f 20/6/21 52/5/21 19/5/21
f 26/9/22 44/4/22 45/9/22
f 8/6/23 38/15/23 9/15/23
f 19/5/24 53/7/24 18/7/24
f 15/4/25 31/1/25 5/1/25
f 25/10/26 45/9/26 46/10/26
f 56/12/27 57/16/27 55/17/27
f 58/18/28 59/19/28 57/16/28
f 60/20/29 61/21/29 59/19/29
f 62/22/30 63/23/30 61/21/30
f 64/24/31 65/25/31 63/23/31
f 66/26/32 67/27/32 65/25/32
f 67/27/33 70/28/33 69/29/33
f 69/29/34 72/30/34 71/31/34
f 72/30/35 73/32/35 71/31/35
f 73/32/36 76/33/36 75/34/36
f 76/33/37 77/35/37 75/34/37
f 78/36/38 79/37/38 77/35/38
f 80/38/39 81/39/39 79/37/39
f 83/40/40 86/41/40 85/42/40
f 85/42/41 88/43/41 87/44/41
f 88/43/42 89/45/42 87/44/42
f 90/46/43 91/47/43 89/45/43
f 91/47/44 94/48/44 93/49/44
f 94/48/45 95/50/45 93/49/45
f 96/51/46 97/52/46 95/50/46
f 98/53/47 99/54/47 97/52/47
f 99/54/48 102/55/48 101/56/48
f 102/55/49 103/57/49 101/56/49
f 104/58/50 105/59/50 103/57/50
f 56/60/1 109/61/1 159/60/1
f 106/62/51 107/63/51 105/59/51
f 108/61/52 55/64/52 107/63/52
f 94/48/1 125/65/1 123/48/1
f 64/24/1 151/26/1 66/26/1
f 82/66/53 136/39/53 81/39/53
f 80/38/1 135/66/1 82/66/1
f 79/37/16 136/39/16 138/37/16
f 88/43/1 131/41/1 129/43/1
f 87/44/16 132/42/16 85/42/16
f 104/58/1 115/55/1 113/58/1
f 103/57/16 116/56/16 101/56/16
f 58/18/1 157/20/1 60/20/1
f 102/55/1 117/67/1 115/55/1
f 74/68/1 141/33/1 76/33/1
f 95/50/16 124/49/16 93/49/16
f 68/69/1 147/28/1 70/28/1
f 56/12/1 160/18/1 58/18/1
f 72/30/1 143/68/1 74/68/1
f 97/52/16 122/50/16 95/50/16
f 96/51/1 123/48/1 121/51/1
f 112/59/54 113/58/54 114/57/54
f 118/54/37 119/53/37 120/52/37
f 126/47/34 123/48/34 125/65/34
f 130/44/31 131/41/31 132/42/31
f 138/37/48 139/36/48 140/35/48
f 144/32/45 145/30/45 146/31/45
f 150/27/42 151/26/42 152/25/42
f 156/21/55 157/20/55 158/19/55
f 93/49/16 126/47/16 91/47/16
f 60/20/1 155/22/1 62/22/1
f 77/35/16 138/37/16 140/35/16
f 126/47/33 127/46/33 128/45/33
f 128/45/32 129/43/32 130/44/32
f 59/19/16 156/21/16 158/19/16
f 86/41/1 134/70/1 131/41/1
f 67/27/16 148/29/16 150/27/16
f 132/42/30 134/70/30 133/40/30
f 92/65/1 127/46/1 125/65/1
f 136/39/49 137/38/49 138/37/49
f 76/33/1 139/36/1 78/36/1
f 85/42/16 133/40/16 83/40/16
f 140/35/47 141/33/47 142/34/47
f 65/25/16 150/27/16 152/25/16
f 144/32/46 141/33/46 143/68/46
f 75/34/16 140/35/16 142/34/16
f 55/64/16 110/63/16 107/63/16
f 99/54/16 120/52/16 97/52/16
f 83/40/56 134/70/56 84/70/56
f 146/31/44 147/28/44 148/29/44
f 55/17/16 161/16/16 162/17/16
f 108/61/1 111/62/1 109/61/1
f 148/29/43 149/69/43 150/27/43
f 57/16/16 158/19/16 161/16/16
f 63/23/16 152/25/16 154/23/16
f 71/31/16 144/32/16 146/31/16
f 101/56/16 118/54/16 99/54/16
f 152/25/41 153/24/41 154/23/41
f 98/53/1 121/51/1 119/53/1
f 90/46/1 129/43/1 127/46/1
f 154/23/40 155/22/40 156/21/40
f 73/32/16 142/34/16 144/32/16
f 107/63/16 112/59/16 105/59/16
f 70/28/1 145/30/1 72/30/1
f 100/67/1 119/53/1 117/67/1
f 158/19/57 160/18/57 161/16/57
f 69/29/16 146/31/16 148/29/16
f 89/45/16 130/44/16 87/44/16
f 161/16/58 159/12/58 162/17/58
f 62/22/1 153/24/1 64/24/1
f 162/64/59 109/61/59 110/63/59
f 66/26/1 149/69/1 68/69/1
f 110/63/60 111/62/60 112/59/60
f 106/62/1 113/58/1 111/62/1
f 91/47/16 128/45/16 89/45/16
f 61/21/16 154/23/16 156/21/16
f 114/57/39 115/55/39 116/56/39
f 116/56/38 117/67/38 118/54/38
f 105/59/16 114/57/16 103/57/16
f 78/36/1 137/38/1 80/38/1
f 120/52/36 121/51/36 122/50/36
f 122/50/35 123/48/35 124/49/35
f 3/3/61 1/12/61 4/8/61
f 4/8/61 6/7/61 3/3/61
f 6/7/61 7/5/61 3/3/61
f 7/5/61 8/6/61 3/3/61
f 8/6/61 9/15/61 3/3/61
f 9/15/61 10/14/61 3/3/61
f 10/14/61 11/13/61 5/1/61
f 3/3/61 10/14/61 5/1/61
f 11/13/61 12/11/61 5/1/61
f 12/11/61 13/10/61 5/1/61
f 13/10/61 14/9/61 5/1/61
f 14/9/61 15/4/61 5/1/61
f 27/4/61 26/9/61 2/2/61
f 26/9/61 25/10/61 2/2/61
f 25/10/61 24/11/61 2/2/61
f 24/11/61 23/13/61 2/2/61
f 23/13/61 22/14/61 2/2/61
f 22/14/61 21/15/61 3/3/61
f 21/15/61 20/6/61 3/3/61
f 20/6/61 19/5/61 3/3/61
f 19/5/61 18/7/61 3/3/61
f 18/7/61 17/8/61 3/3/61
f 17/8/61 16/12/61 3/3/61
f 22/14/61 3/3/61 2/2/61
f 32/4/62 33/9/62 30/2/62
f 33/9/62 34/10/62 30/2/62
f 34/10/62 35/11/62 30/2/62
f 35/11/62 36/13/62 30/2/62
f 36/13/62 37/14/62 30/2/62
f 37/14/62 38/15/62 29/3/62
f 38/15/62 39/6/62 29/3/62
f 39/6/62 40/5/62 29/3/62
f 40/5/62 41/7/62 29/3/62
f 41/7/62 42/8/62 29/3/62
f 42/8/62 28/12/62 29/3/62
f 37/14/62 29/3/62 30/2/62
f 29/3/62 43/12/62 54/8/62
f 54/8/62 53/7/62 29/3/62
f 53/7/62 52/5/62 29/3/62
f 52/5/62 51/6/62 29/3/62
f 51/6/62 50/15/62 29/3/62
f 50/15/62 49/14/62 29/3/62
f 49/14/62 48/13/62 31/1/62
f 29/3/62 49/14/62 31/1/62
f 48/13/62 47/11/62 31/1/62
f 47/11/62 46/10/62 31/1/62
f 46/10/62 45/9/62 31/1/62
f 45/9/62 44/4/62 31/1/62
f 7/5/2 40/5/2 39/6/2
f 18/7/3 53/7/3 54/8/3
f 15/4/63 14/9/63 33/9/63
f 25/10/5 46/10/5 47/11/5
f 6/7/6 41/7/6 40/5/6
f 17/8/7 54/8/7 43/12/7
f 14/9/8 13/10/8 34/10/8
f 24/11/9 47/11/9 48/13/9
f 4/8/10 42/8/10 41/7/10
f 12/11/11 35/11/11 34/10/11
f 23/13/12 48/13/12 49/14/12
f 1/12/13 28/12/13 42/8/13
f 11/13/14 36/13/14 35/11/14
f 22/14/15 49/14/15 50/15/15
f 3/3/16 29/3/16 28/12/16
f 16/12/16 43/12/16 29/3/16
f 10/14/17 37/14/17 36/13/17
f 21/15/18 50/15/18 51/6/18
f 5/1/19 31/1/19 44/4/19
f 9/15/20 38/15/20 37/14/20
f 20/6/21 51/6/21 52/5/21
f 26/9/64 27/4/64 44/4/64
f 8/6/23 39/6/23 38/15/23
f 19/5/24 52/5/24 53/7/24
f 15/4/25 32/4/25 31/1/25
f 25/10/26 26/9/26 45/9/26
f 56/12/27 58/18/27 57/16/27
f 58/18/28 60/20/28 59/19/28
f 60/20/29 62/22/29 61/21/29
f 62/22/30 64/24/30 63/23/30
f 64/24/31 66/26/31 65/25/31
f 66/26/32 68/69/32 67/27/32
f 67/27/33 68/69/33 70/28/33
f 69/29/34 70/28/34 72/30/34
f 72/30/35 74/68/35 73/32/35
f 73/32/36 74/68/36 76/33/36
f 76/33/37 78/36/37 77/35/37
f 78/36/38 80/38/38 79/37/38
f 80/38/39 82/66/39 81/39/39
f 83/40/40 84/70/40 86/41/40
f 85/42/41 86/41/41 88/43/41
f 88/43/42 90/46/42 89/45/42
f 90/46/43 92/65/43 91/47/43
f 91/47/44 92/65/44 94/48/44
f 94/48/45 96/51/45 95/50/45
f 96/51/46 98/53/46 97/52/46
f 98/53/47 100/67/47 99/54/47
f 99/54/48 100/67/48 102/55/48
f 102/55/49 104/58/49 103/57/49
f 104/58/50 106/62/50 105/59/50
f 56/60/1 108/61/1 109/61/1
f 106/62/51 108/61/51 107/63/51
f 108/61/52 56/60/52 55/64/52
f 94/48/1 92/65/1 125/65/1
f 64/24/1 153/24/1 151/26/1
f 82/66/53 135/66/53 136/39/53
f 80/38/1 137/38/1 135/66/1
f 79/37/16 81/39/16 136/39/16
f 88/43/1 86/41/1 131/41/1
f 87/44/16 130/44/16 132/42/16
f 104/58/1 102/55/1 115/55/1
f 103/57/16 114/57/16 116/56/16
f 58/18/1 160/18/1 157/20/1
f 102/55/1 100/67/1 117/67/1
f 74/68/1 143/68/1 141/33/1
f 95/50/16 122/50/16 124/49/16
f 68/69/1 149/69/1 147/28/1
f 56/12/1 159/12/1 160/18/1
f 72/30/1 145/30/1 143/68/1
f 97/52/16 120/52/16 122/50/16
f 96/51/1 94/48/1 123/48/1
f 112/59/54 111/62/54 113/58/54
f 118/54/37 117/67/37 119/53/37
f 126/47/34 124/49/34 123/48/34
f 130/44/31 129/43/31 131/41/31
f 138/37/48 137/38/48 139/36/48
f 144/32/45 143/68/45 145/30/45
f 150/27/42 149/69/42 151/26/42
f 156/21/55 155/22/55 157/20/55
f 93/49/16 124/49/16 126/47/16
f 60/20/1 157/20/1 155/22/1
f 77/35/16 79/37/16 138/37/16
f 126/47/33 125/65/33 127/46/33
f 128/45/32 127/46/32 129/43/32
f 59/19/16 61/21/16 156/21/16
f 86/41/1 84/70/1 134/70/1
f 67/27/16 69/29/16 148/29/16
f 132/42/30 131/41/30 134/70/30
f 92/65/1 90/46/1 127/46/1
f 136/39/49 135/66/49 137/38/49
f 76/33/1 141/33/1 139/36/1
f 85/42/16 132/42/16 133/40/16
f 140/35/47 139/36/47 141/33/47
f 65/25/16 67/27/16 150/27/16
f 144/32/46 142/34/46 141/33/46
f 75/34/16 77/35/16 140/35/16
f 55/64/16 162/64/16 110/63/16
f 99/54/16 118/54/16 120/52/16
f 83/40/56 133/40/56 134/70/56
f 146/31/44 145/30/44 147/28/44
f 55/17/16 57/16/16 161/16/16
f 108/61/1 106/62/1 111/62/1
f 148/29/43 147/28/43 149/69/43
f 57/16/16 59/19/16 158/19/16
f 63/23/16 65/25/16 152/25/16
f 71/31/16 73/32/16 144/32/16
f 101/56/16 116/56/16 118/54/16
f 152/25/41 151/26/41 153/24/41
f 98/53/1 96/51/1 121/51/1
f 90/46/1 88/43/1 129/43/1
f 154/23/40 153/24/40 155/22/40
f 73/32/16 75/34/16 142/34/16
f 107/63/16 110/63/16 112/59/16
f 70/28/1 147/28/1 145/30/1
f 100/67/1 98/53/1 119/53/1
f 158/19/57 157/20/57 160/18/57
f 69/29/16 71/31/16 146/31/16
f 89/45/16 128/45/16 130/44/16
f 161/16/58 160/18/58 159/12/58
f 62/22/1 155/22/1 153/24/1
f 162/64/59 159/60/59 109/61/59
f 66/26/1 151/26/1 149/69/1
f 110/63/60 109/61/60 111/62/60
f 106/62/1 104/58/1 113/58/1
f 91/47/16 126/47/16 128/45/16
f 61/21/16 63/23/16 154/23/16
f 114/57/39 113/58/39 115/55/39
f 116/56/38 115/55/38 117/67/38
f 105/59/16 112/59/16 114/57/16
f 78/36/1 139/36/1 137/38/1
f 120/52/36 119/53/36 121/51/36
f 122/50/35 121/51/35 123/48/35

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class Animation extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class AudioSettings extends Settings {
public class AudioSettings extends ClientState {
}

View File

@@ -1,4 +1,5 @@
package pp.mdga.client;
public class Ceremony extends ClientState {
private final CeremonyStateMachine ceremonyStateMachine = new CeremonyStateMachine();
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class CeremonyStateMachine extends ClientStateMachine {
}

View File

@@ -1,4 +1,5 @@
package pp.mdga.client;
public class ChoosePiece extends Turn {
public class ChoosePiece extends ClientState {
private final ChoosePieceStateMachine choosePieceStateMachine = new ChoosePieceStateMachine();
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class ChoosePieceStateMachine extends ClientStateMachine{
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class ChoosePowerCard extends PowerCard {
public class ChoosePowerCard extends ClientState {
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class ClientAutomaton extends ClientStateMachine {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class ClientState {
public abstract class ClientState {
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public abstract class ClientStateMachine extends ClientState {
}

View File

@@ -1,4 +1,5 @@
package pp.mdga.client;
public class DetermineStartPlayer extends Game {
public class DetermineStartPlayer extends ClientState {
private final DetermineStartPlayerStateMachine determineStartPlayerStateMachine = new DetermineStartPlayerStateMachine();
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class DetermineStartPlayerStateMachine extends ClientStateMachine{
}

View File

@@ -1,4 +1,5 @@
package pp.mdga.client;
public class Dialogs extends ClientState {
private final DialogsStateMachine dialogsStateMachine = new DialogsStateMachine();
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class DialogsStateMachine extends ClientStateMachine {
}

View File

@@ -1,4 +0,0 @@
package pp.mdga.client;
public class Game extends ClientState {
}

View File

@@ -0,0 +1,5 @@
package pp.mdga.client;
public class GameState extends ClientState {
private final GameStateMachine gameStateMachine = new GameStateMachine();
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class GameStateMachine extends ClientStateMachine {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class Lobby extends Dialogs {
public class Lobby extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class MainSettings extends Settings {
public class MainSettings extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class MovePiece extends Turn {
public class MovePiece extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class NetworkDialog extends Dialogs {
public class NetworkDialog extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class NoPiece extends ChoosePiece {
public class NoPiece extends ClientState {
}

View File

@@ -1,4 +1,4 @@
package pp.mdga.client;
public class PlayPowerCard extends PowerCard {
public class PlayPowerCard extends ClientState {
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client;
public class Podium extends ClientState {
}

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