Compare commits
100 Commits
main
..
82db2bdab1
| Author | SHA1 | Date | |
|---|---|---|---|
| 82db2bdab1 | |||
| 96ed5ac483 | |||
| a9d9d209b9 | |||
| 86307e997b | |||
| ae8f33e598 | |||
| dcfea1854c | |||
| 111d089b1f | |||
| 607d6d104e | |||
| 1e4c772a66 | |||
| ccc0dc2972 | |||
| 0f61b25d4f | |||
| e015f2af81 | |||
| 3e9e0edd70 | |||
| e094a210f4 | |||
| 850c5aa985 | |||
| 96b999dd39 | |||
| ee0f2384be | |||
| 114cae0d6c | |||
| 07633da4ee | |||
| a5b00ac0a1 | |||
| 891e47ffec | |||
| d26d6646c5 | |||
| d2468557b5 | |||
| e44e0db63e | |||
| 3b9becbbda | |||
| 2e9549e4e0 | |||
| c2a81febb9 | |||
| 0e6658c2d9 | |||
| 93e341d445 | |||
| b5d82ac8de | |||
| 155049830b | |||
| 94ac10e93b | |||
| b20f300260 | |||
| 8c719a8835 | |||
| 3adaeffe2d | |||
| ee2367643d | |||
| bf87f4af1c | |||
| f7d753e7e0 | |||
| 4eb1b61e7b | |||
| 298167d4c9 | |||
| 7a25d3b881 | |||
| 50fe4b7681 | |||
| a977e4dca1 | |||
| 238c67ce48 | |||
| 2d3477ffc5 | |||
| 62b6c3fd81 | |||
| 62f04dfded | |||
| 6fe8a70d9e | |||
| 1e5ed45c63 | |||
| 44162b5bf3 | |||
| 64152219a0 | |||
| 99c4f68893 | |||
| 5e428d1301 | |||
| e5e67a3418 | |||
| 1fc7103d66 | |||
| 17ec7a1a90 | |||
| 4a6e1e81e4 | |||
| fb400afdc2 | |||
| 3bd95c0b61 | |||
| a9e4644b06 | |||
| 442fc6c7d0 | |||
| c7344a502f | |||
| 4cd5e90e2b | |||
| 3179a17b36 | |||
| db07bfa453 | |||
| 1cc4c3eeb9 | |||
| 766e923713 | |||
| 34f6d9848b | |||
| 6fc1c9429e | |||
| 5cf4bc506f | |||
| 3e9b9d1f31 | |||
| 96a2d43aaf | |||
| 9bc2d08ddd | |||
| 73ff37cc38 | |||
| 2b86d0d86c | |||
| 7f33529e52 | |||
| 4ed23e1a0f | |||
| 385c6ba50a | |||
| 270bc40fa3 | |||
| 67bb44eb39 | |||
| 544f9c0877 | |||
| 36deb15f02 | |||
| a24e8b0223 | |||
| b6868db2c6 | |||
| 649fd581f8 | |||
| d1acde7bde | |||
| 74c5e7709a | |||
| a0b483a4f0 | |||
| f04ee9177f | |||
| 5d9c958732 | |||
| 4946c214be | |||
| ceb4c49e01 | |||
| 7f84889a02 | |||
| 7e1d15591e | |||
| 2f1794973a | |||
| eba221525f | |||
| c301d08094 | |||
| bba7153801 | |||
| b32ff5aa6f | |||
| ca5401cbe2 |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
@@ -16,7 +16,7 @@ import eu.jonahbauer.wizard.common.model.Card;
|
||||
public class InstructionScreen extends MenuScreen {
|
||||
private static final int MAX_PAGE = 3;
|
||||
|
||||
private TextButton buttonBack;
|
||||
private TextButton buttonOK;
|
||||
private VerticalGroup content;
|
||||
private ScrollPane scrollPane;
|
||||
private TextButton nextPageButton;
|
||||
@@ -29,7 +29,7 @@ public class InstructionScreen extends MenuScreen {
|
||||
private final ChangeListener listener = new ChangeListener() {
|
||||
@Override
|
||||
public void changed(ChangeEvent event, Actor actor) {
|
||||
if (actor == buttonBack) {
|
||||
if (actor == buttonOK) {
|
||||
game.getClient().execute(Menu.class, Menu::showMenuScreen);
|
||||
sfxClick();
|
||||
} else if (actor == nextPageButton) {
|
||||
@@ -70,9 +70,9 @@ public class InstructionScreen extends MenuScreen {
|
||||
previousPageButton.addListener(listener);
|
||||
getButtonGroup().addActor(previousPageButton);
|
||||
|
||||
buttonBack = new TextButton(messages.get("menu.instruction.back"), skin);
|
||||
buttonBack.addListener(listener);
|
||||
getButtonGroup().addActor(buttonBack);
|
||||
buttonOK = new TextButton(messages.get("menu.instruction.back"), skin);
|
||||
buttonOK.addListener(listener);
|
||||
getButtonGroup().addActor(buttonOK);
|
||||
|
||||
nextPageButton = new TextButton(messages.get("menu.instruction.nextPageButton"), skin);
|
||||
nextPageButton.addListener(listener);
|
||||
@@ -83,7 +83,7 @@ public class InstructionScreen extends MenuScreen {
|
||||
scrollPane.setSize(0.65f * WizardGame.WIDTH, 400 + 0.1f * WizardGame.HEIGHT + 80);
|
||||
stage.addActor(scrollPane);
|
||||
|
||||
stage.addCaptureListener(new KeyboardFocusManager(scrollPane, previousPageButton, buttonBack, nextPageButton));
|
||||
stage.addCaptureListener(new KeyboardFocusManager(scrollPane, previousPageButton, buttonOK, nextPageButton));
|
||||
|
||||
showFirstPage();
|
||||
}
|
||||
@@ -166,8 +166,9 @@ public class InstructionScreen extends MenuScreen {
|
||||
reset();
|
||||
|
||||
startSection("menu.instruction.variant.title");
|
||||
addParagraph("menu.instruction.variant.intro");
|
||||
|
||||
Label variantsIntro = new Label(messages.get("menu.instruction.variant.intro"), skin);
|
||||
content.addActor(variantsIntro);
|
||||
Table table = new Table(skin).padTop(10);
|
||||
table.defaults().space(10.0f).left().top();
|
||||
table.columnDefaults(1).grow();
|
||||
|
||||
@@ -70,6 +70,6 @@ public class CardUtil {
|
||||
);
|
||||
|
||||
public Card.Suit getDefaultTrumpSuit(Card card) {
|
||||
return card == null ? Card.Suit.NONE : DEFAULT_SUITES.get(card);
|
||||
return DEFAULT_SUITES.get(card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package eu.jonahbauer.wizard.common.messages.server;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class KickVotedMessage extends ServerMessage {
|
||||
/**
|
||||
* UUID of the voting player
|
||||
*/
|
||||
private final @NonNull UUID voter;
|
||||
/**
|
||||
* UUID of player who is supposed to be kicked
|
||||
*/
|
||||
private final @NonNull UUID player;
|
||||
/**
|
||||
* Time until the vote ends in {@link System#currentTimeMillis() UNIX time}
|
||||
*/
|
||||
private final long timeout;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package eu.jonahbauer.wizard.common.messages.server;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class KickedMessage extends ServerMessage {
|
||||
/**
|
||||
* UUID of player who was kicked
|
||||
*/
|
||||
private final @NonNull UUID player;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract sealed class ServerMessage permits AckMessage, GameMessage, NackMessage, PlayerLeftMessage, PlayerModifiedMessage, SessionJoinedMessage, SessionListMessage, SessionModifiedMessage, SessionRemovedMessage, StartingGameMessage {
|
||||
public abstract sealed class ServerMessage permits AckMessage, GameMessage, KickVotedMessage, KickedMessage, NackMessage, PlayerLeftMessage, PlayerModifiedMessage, SessionJoinedMessage, SessionListMessage, SessionModifiedMessage, SessionRemovedMessage, StartingGameMessage {
|
||||
private static final ObjectMapper MAPPER = SerializationUtil.newObjectMapper(ServerMessage.class, ObserverMessage.class);
|
||||
|
||||
public static ServerMessage parse(String json) throws ParseException {
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
package eu.jonahbauer.wizard.core.machine.states.round;
|
||||
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
|
||||
import eu.jonahbauer.wizard.common.model.Card;
|
||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||
import eu.jonahbauer.wizard.core.machine.Game;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||
import eu.jonahbauer.wizard.core.machine.GameState;
|
||||
import eu.jonahbauer.wizard.core.model.card.GameCards;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
|
||||
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PICK_TRUMP;
|
||||
|
||||
public final class DeterminingTrump extends RoundState {
|
||||
private transient UUID player;
|
||||
private transient boolean werewolf;
|
||||
|
||||
public DeterminingTrump(GameData data) {
|
||||
super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS));
|
||||
@@ -26,31 +35,74 @@ public final class DeterminingTrump extends RoundState {
|
||||
var player = entry.getKey();
|
||||
var hand = entry.getValue();
|
||||
if (hand.contains(Card.WEREWOLF)) {
|
||||
this.player = player;
|
||||
this.werewolf = true;
|
||||
game.notify(new TrumpMessage(trumpCard, null));
|
||||
game.notify(new TrumpMessage(Card.WEREWOLF, null));
|
||||
|
||||
var data = getData().with(CURRENT_PLAYER, player);
|
||||
return sync(data, DeterminingTrumpUserInput::new);
|
||||
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
|
||||
return timeout(game);
|
||||
}
|
||||
}
|
||||
|
||||
// default trump handling
|
||||
Card.Suit trumpSuit = trumpCard != null ? GameCards.get(trumpCard).getTrumpSuit() : Card.Suit.NONE;
|
||||
if (trumpSuit == null) {
|
||||
var player = getDealer();
|
||||
this.player = getDealer();
|
||||
game.notify(new TrumpMessage(trumpCard, null));
|
||||
|
||||
var data = getData().with(CURRENT_PLAYER, player);
|
||||
return sync(data, DeterminingTrumpUserInput::new);
|
||||
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
|
||||
return timeout(game);
|
||||
} else {
|
||||
var data = getData().with(
|
||||
TRUMP_SUIT, trumpSuit,
|
||||
CURRENT_PLAYER, getNextPlayer(getDealer())
|
||||
);
|
||||
|
||||
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
|
||||
|
||||
return sync(data, Predicting::new);
|
||||
return transition(game, trumpSuit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onTimeout(Game game) {
|
||||
game.notify(new TimeoutMessage());
|
||||
Card.Suit[] suits;
|
||||
if (werewolf) {
|
||||
suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE};
|
||||
} else {
|
||||
suits = new Card.Suit[]{Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW};
|
||||
}
|
||||
return transition(game, suits[game.getRandom().nextInt(suits.length)]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||
if (this.player.equals(player) && message instanceof PickTrumpMessage trumpMessage) {
|
||||
checkTrumpSuit(trumpMessage.getTrumpSuit());
|
||||
return transition(game, trumpMessage.getTrumpSuit());
|
||||
} else {
|
||||
return super.onMessage(game, player, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTrumpSuit(Card.Suit suit) {
|
||||
if (!werewolf && suit == Card.Suit.NONE) {
|
||||
throw new IllegalArgumentException("Trump suit must not be " + Card.Suit.NONE + ".");
|
||||
} else if (suit == null) {
|
||||
throw new IllegalArgumentException("Trump suit must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<GameState> transition(Game game, @NotNull Card.Suit trumpSuit) {
|
||||
GameData data = getData().with(
|
||||
TRUMP_SUIT, trumpSuit,
|
||||
CURRENT_PLAYER, getNextPlayer(getDealer())
|
||||
);
|
||||
|
||||
if (werewolf) {
|
||||
var mutableHands = new HashMap<>(get(HANDS));
|
||||
var mutableHand = new ArrayList<>(mutableHands.get(player));
|
||||
mutableHand.set(mutableHand.indexOf(Card.WEREWOLF), get(TRUMP_CARD));
|
||||
mutableHands.put(player, List.copyOf(mutableHand));
|
||||
data = data.with(HANDS, Map.copyOf(mutableHands));
|
||||
game.notify(new TrumpMessage(Card.WEREWOLF, trumpSuit));
|
||||
game.notify(player, new HandMessage(player, mutableHands.get(player)));
|
||||
} else {
|
||||
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
|
||||
}
|
||||
return sync(data, Predicting::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package eu.jonahbauer.wizard.core.machine.states.round;
|
||||
|
||||
import eu.jonahbauer.wizard.common.messages.observer.HandMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.TrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
|
||||
import eu.jonahbauer.wizard.common.model.Card;
|
||||
import eu.jonahbauer.wizard.core.machine.Game;
|
||||
import eu.jonahbauer.wizard.core.machine.GameState;
|
||||
import eu.jonahbauer.wizard.core.machine.states.GameData;
|
||||
import eu.jonahbauer.wizard.core.machine.states.TransientState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.PICK_TRUMP;
|
||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
|
||||
import static eu.jonahbauer.wizard.core.machine.states.GameData.TRUMP_CARD;
|
||||
|
||||
public final class DeterminingTrumpUserInput extends RoundState implements TransientState {
|
||||
private final transient UUID player;
|
||||
private final transient boolean werewolf;
|
||||
|
||||
public DeterminingTrumpUserInput(GameData data) {
|
||||
super(data.require(TRUMP_CARD).requireEach(PLAYERS, HANDS).require(CURRENT_PLAYER));
|
||||
|
||||
this.player = get(CURRENT_PLAYER);
|
||||
this.werewolf = get(HANDS).get(this.player).contains(Card.WEREWOLF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onEnter(Game game) {
|
||||
game.notify(new UserInputMessage(this.player, PICK_TRUMP, getTimeout(game, true)));
|
||||
return timeout(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onTimeout(Game game) {
|
||||
game.notify(new TimeoutMessage());
|
||||
|
||||
Card.Suit[] suits;
|
||||
if (werewolf) {
|
||||
suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW, Card.Suit.NONE};
|
||||
} else {
|
||||
suits = new Card.Suit[] {Card.Suit.BLUE, Card.Suit.GREEN, Card.Suit.RED, Card.Suit.YELLOW};
|
||||
}
|
||||
return transition(game, suits[game.getRandom().nextInt(suits.length)]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
|
||||
if (this.player.equals(player) && message instanceof PickTrumpMessage trumpMessage) {
|
||||
checkTrumpSuit(trumpMessage.getTrumpSuit());
|
||||
return transition(game, trumpMessage.getTrumpSuit());
|
||||
} else {
|
||||
return super.onMessage(game, player, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTrumpSuit(Card.Suit suit) {
|
||||
if (!werewolf && suit == Card.Suit.NONE) {
|
||||
throw new IllegalArgumentException("Trump suit must not be " + Card.Suit.NONE + ".");
|
||||
} else if (suit == null) {
|
||||
throw new IllegalArgumentException("Trump suit must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<GameState> transition(Game game, @NotNull Card.Suit trumpSuit) {
|
||||
GameData data = getData().with(
|
||||
TRUMP_SUIT, trumpSuit,
|
||||
CURRENT_PLAYER, getNextPlayer(getDealer())
|
||||
);
|
||||
|
||||
if (werewolf) {
|
||||
var mutableHands = new HashMap<>(get(HANDS));
|
||||
var mutableHand = new ArrayList<>(mutableHands.get(player));
|
||||
mutableHand.set(mutableHand.indexOf(Card.WEREWOLF), get(TRUMP_CARD));
|
||||
mutableHands.put(player, List.copyOf(mutableHand));
|
||||
data = data.with(HANDS, Map.copyOf(mutableHands));
|
||||
game.notify(new TrumpMessage(Card.WEREWOLF, trumpSuit));
|
||||
game.notify(player, new HandMessage(player, mutableHands.get(player)));
|
||||
} else {
|
||||
game.notify(new TrumpMessage(get(TRUMP_CARD), trumpSuit));
|
||||
}
|
||||
return sync(data, Predicting::new);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public class DeterminingTrumpTest {
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private Game performTest(GameConfiguration configuration, int round, Map<UUID, List<Card>> hands, Card trumpCard, MessageQueue queue) {
|
||||
Game game = spy(new Game(configuration, queue));
|
||||
doFinish().when(game).transition(argThat(argument -> argument instanceof SyncState && argument.getData().has(TRUMP_SUIT)));
|
||||
doFinish().when(game).transition(any(SyncState.class));
|
||||
queue.setGame(game);
|
||||
|
||||
var playerList = List.of(players);
|
||||
@@ -92,8 +92,7 @@ public class DeterminingTrumpTest {
|
||||
);
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players);
|
||||
MessageQueue queue = new MessageQueue();
|
||||
|
||||
Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.GREEN_JESTER, queue);
|
||||
|
||||
@@ -118,7 +117,6 @@ public class DeterminingTrumpTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addPickTrump(players[0], Card.Suit.GREEN);
|
||||
|
||||
Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.BLUE_WIZARD, queue);
|
||||
@@ -146,7 +144,6 @@ public class DeterminingTrumpTest {
|
||||
|
||||
// play cards in given order
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players)
|
||||
.addPickTrump(players[3], Card.Suit.YELLOW);
|
||||
|
||||
Game game = performTest(Configurations.ANNIVERSARY_2021, 0, hands, Card.GREEN_1, queue);
|
||||
|
||||
@@ -148,11 +148,10 @@ public class RoundTest {
|
||||
@Test
|
||||
public void run_Anniversary() throws ExecutionException, InterruptedException {
|
||||
MessageQueue queue = new MessageQueue()
|
||||
.sync(players) // starting_round
|
||||
.sync(players) // dealing
|
||||
.sync(players) // determining_trump
|
||||
.sync(players)
|
||||
.sync(players)
|
||||
.addPickTrump(players[2], Card.Suit.YELLOW)
|
||||
.sync(players) // determining_trump
|
||||
.sync(players)
|
||||
.addPrediction(players[3], 2)
|
||||
.addPrediction(players[0], 2)
|
||||
.addPrediction(players[1], 2)
|
||||
|
||||