game logic
parent
640443abbc
commit
7947e54872
@ -0,0 +1,10 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx.actions;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Action;
|
||||||
|
|
||||||
|
public class WaitAction extends Action {
|
||||||
|
@Override
|
||||||
|
public boolean act(float delta) {
|
||||||
|
return getTarget().getActions().size == 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay;
|
||||||
|
|
||||||
|
public interface InteractionOverlay {
|
||||||
|
}
|
@ -0,0 +1,245 @@
|
|||||||
|
package eu.jonahbauer.wizard.client.libgdx.state;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.Client;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
|
||||||
|
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.data.SessionData;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.observer.*;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.GameMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.model.Card;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Getter
|
||||||
|
public final class Game extends BaseState {
|
||||||
|
private final UUID self;
|
||||||
|
private final UUID session;
|
||||||
|
private final String sessionName;
|
||||||
|
private final String secret;
|
||||||
|
|
||||||
|
private final Map<UUID, String> players;
|
||||||
|
private final Map<UUID, Integer> scores = new HashMap<>();
|
||||||
|
|
||||||
|
private int round = -1;
|
||||||
|
private final Map<UUID, Integer> predictions = new HashMap<>();
|
||||||
|
private final Map<UUID, List<Card>> hands = new HashMap<>();
|
||||||
|
private final Map<UUID, List<List<Card>>> tricks = new HashMap<>();
|
||||||
|
|
||||||
|
private int trick = -1;
|
||||||
|
private final List<Pair<UUID, Card>> stack = new ArrayList<>();
|
||||||
|
|
||||||
|
private Card trumpCard;
|
||||||
|
private Card.Suit trumpSuit;
|
||||||
|
|
||||||
|
private GameScreen gameScreen;
|
||||||
|
|
||||||
|
public Game(UUID self, UUID session, String sessionName, String secret, Map<UUID, String> players) {
|
||||||
|
this.self = self;
|
||||||
|
this.session = session;
|
||||||
|
this.sessionName = sessionName;
|
||||||
|
this.secret = secret;
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onEnter(Client client) {
|
||||||
|
gameScreen = new GameScreen(client.getGame());
|
||||||
|
client.getGame().setScreen(gameScreen);
|
||||||
|
return super.onEnter(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onMessage(Client client, ServerMessage message) {
|
||||||
|
log(message);
|
||||||
|
|
||||||
|
if (message instanceof GameMessage game) {
|
||||||
|
var observerMessage = game.getObserverMessage();
|
||||||
|
if (observerMessage instanceof StateMessage state) {
|
||||||
|
switch (state.getState()) {
|
||||||
|
case "starting_round" -> {
|
||||||
|
round ++;
|
||||||
|
predictions.clear();
|
||||||
|
tricks.clear();
|
||||||
|
trumpSuit = null;
|
||||||
|
trumpCard = null;
|
||||||
|
stack.clear();
|
||||||
|
trick = -1;
|
||||||
|
gameScreen.startRound(round);
|
||||||
|
}
|
||||||
|
case "starting_trick" -> {
|
||||||
|
trick ++;
|
||||||
|
stack.clear();
|
||||||
|
gameScreen.startTrick();
|
||||||
|
}
|
||||||
|
case "finished", "error" -> {
|
||||||
|
return returnToSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof HandMessage hand) {
|
||||||
|
hands.put(hand.getPlayer(), hand.getHand());
|
||||||
|
gameScreen.setHand(hand.getPlayer(), hand.getHand());
|
||||||
|
} else if (observerMessage instanceof PredictionMessage prediction) {
|
||||||
|
predictions.put(prediction.getPlayer(), prediction.getPrediction());
|
||||||
|
gameScreen.addPrediction(round, prediction.getPlayer(), prediction.getPrediction());
|
||||||
|
} else if (observerMessage instanceof TrumpMessage trump) {
|
||||||
|
trumpCard = trump.getCard();
|
||||||
|
trumpSuit = trump.getSuit();
|
||||||
|
gameScreen.setTrump(trumpCard, trumpSuit);
|
||||||
|
} else if (observerMessage instanceof TrickMessage trick) {
|
||||||
|
this.stack.clear();
|
||||||
|
this.tricks.computeIfAbsent(trick.getPlayer(), player -> new ArrayList<>())
|
||||||
|
.add(trick.getCards());
|
||||||
|
gameScreen.finishTrick(trick.getPlayer(), trick.getCards());
|
||||||
|
} else if (observerMessage instanceof CardMessage card) {
|
||||||
|
this.stack.add(Pair.of(card.getPlayer(), card.getCard()));
|
||||||
|
|
||||||
|
var handCard = switch (card.getCard()) {
|
||||||
|
case CHANGELING_JESTER, CHANGELING_WIZARD -> Card.CHANGELING;
|
||||||
|
case JUGGLER_BLUE, JUGGLER_GREEN, JUGGLER_RED, JUGGLER_YELLOW -> Card.JUGGLER;
|
||||||
|
case CLOUD_BLUE, CLOUD_GREEN, CLOUD_RED, CLOUD_YELLOW -> Card.CLOUD;
|
||||||
|
default -> card.getCard();
|
||||||
|
};
|
||||||
|
|
||||||
|
var hand = this.hands.get(card.getPlayer());
|
||||||
|
if (hand != null) {
|
||||||
|
hand.remove(handCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
gameScreen.playCard(card.getPlayer(), handCard);
|
||||||
|
} else if (observerMessage instanceof ScoreMessage score) {
|
||||||
|
score.getPoints().forEach((player, points) -> scores.merge(player, points, Integer::sum));
|
||||||
|
gameScreen.addScores(round, score.getPoints());
|
||||||
|
} else if (observerMessage instanceof UserInputMessage input) {
|
||||||
|
if (input.getAction() == UserInputMessage.Action.SYNC) {
|
||||||
|
gameScreen.sync();
|
||||||
|
} else {
|
||||||
|
gameScreen.setActivePlayer(input.getPlayer(), input.getAction(), input.getTimeout());
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof TimeoutMessage) {
|
||||||
|
gameScreen.timeout();
|
||||||
|
} else {
|
||||||
|
return Optional.of(new Menu());
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
} else if (message instanceof NackMessage nack) {
|
||||||
|
int code = nack.getCode();
|
||||||
|
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
||||||
|
gameScreen.addMessage(nack.getMessage());
|
||||||
|
gameScreen.ready(false);
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
return unexpectedMessage(client, message);
|
||||||
|
}
|
||||||
|
} else if (message instanceof AckMessage) {
|
||||||
|
gameScreen.ready(true);
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
return unexpectedMessage(client, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<ClientState> returnToSession() {
|
||||||
|
return Optional.of(new Session(
|
||||||
|
new SessionData(session, sessionName, -1, null),
|
||||||
|
players.entrySet().stream()
|
||||||
|
.map(entry -> new PlayerData(entry.getKey(), entry.getValue(), false))
|
||||||
|
.toList(),
|
||||||
|
self, secret
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(ServerMessage message) {
|
||||||
|
if (message instanceof GameMessage gameMessage) {
|
||||||
|
var observerMessage = gameMessage.getObserverMessage();
|
||||||
|
if (observerMessage instanceof StateMessage state) {
|
||||||
|
switch (state.getState()) {
|
||||||
|
case "starting_round" -> log.info("Round {} is starting...", round + 1);
|
||||||
|
case "starting_trick" -> log.info("Trick {} is starting...", trick + 1);
|
||||||
|
case "finished" -> log.info("The game has finished.");
|
||||||
|
case "error" -> log.info("The game has finished with an error.");
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof HandMessage hand) {
|
||||||
|
if (hand.getPlayer().equals(self)) {
|
||||||
|
log.info("Your hand cards are: {}", hand.getHand());
|
||||||
|
} else {
|
||||||
|
log.info("{}'s hand cards are: {}", nameOf(hand.getPlayer()), hand.getHand());
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof PredictionMessage prediction) {
|
||||||
|
if (prediction.getPlayer().equals(self)) {
|
||||||
|
log.info("You predicted: {}%n", prediction.getPrediction());
|
||||||
|
} else {
|
||||||
|
log.info("{} predicted: {}%n", nameOf(prediction.getPlayer()), prediction.getPrediction());
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof TrumpMessage trump) {
|
||||||
|
trumpCard = trump.getCard();
|
||||||
|
trumpSuit = trump.getSuit();
|
||||||
|
if (trumpCard == null) {
|
||||||
|
log.info("There is no trump in this round.");
|
||||||
|
} else {
|
||||||
|
log.info("The trump suit is {} ({}).", trumpSuit, trumpCard);
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof TrickMessage trick) {
|
||||||
|
log.info("This trick {} goes to {}.", trick.getCards(), nameOf(trick.getPlayer()));
|
||||||
|
} else if (observerMessage instanceof CardMessage card) {
|
||||||
|
if (card.getPlayer().equals(self)) {
|
||||||
|
log.info("You played {}.", card.getCard());
|
||||||
|
} else {
|
||||||
|
log.info("{} played {}.", nameOf(card.getPlayer()), card.getCard());
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof ScoreMessage score) {
|
||||||
|
log.info("The scores are as follows: " + score.getPoints());
|
||||||
|
} else if (observerMessage instanceof UserInputMessage input) {
|
||||||
|
if (input.getAction() != UserInputMessage.Action.SYNC) {
|
||||||
|
if (self.equals(input.getPlayer())) {
|
||||||
|
log.info("It is your turn to {}. You have time until {}.", switch (input.getAction()) {
|
||||||
|
case CHANGE_PREDICTION -> "change your prediction";
|
||||||
|
case JUGGLE_CARD -> "juggle a card";
|
||||||
|
case PLAY_CARD -> "play a card";
|
||||||
|
case PICK_TRUMP -> "pick the trump suit";
|
||||||
|
case MAKE_PREDICTION -> "make a prediction";
|
||||||
|
default -> throw new AssertionError();
|
||||||
|
}, LocalDateTime.ofInstant(Instant.ofEpochMilli(input.getTimeout()), ZoneId.systemDefault()));
|
||||||
|
} else {
|
||||||
|
log.info(
|
||||||
|
"Waiting for input {} from {}. (times out at {})",
|
||||||
|
input.getAction(),
|
||||||
|
nameOf(input.getPlayer()),
|
||||||
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(input.getTimeout()), ZoneId.systemDefault())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (observerMessage instanceof TimeoutMessage) {
|
||||||
|
log.info("The previous interaction timed out.");
|
||||||
|
} else {
|
||||||
|
log.fatal("Unknown observer message type {}.", observerMessage.getClass());
|
||||||
|
}
|
||||||
|
} else if (message instanceof NackMessage nack) {
|
||||||
|
int code = nack.getCode();
|
||||||
|
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
|
||||||
|
log.error(nack.getMessage());
|
||||||
|
} else {
|
||||||
|
log.fatal("Unexpected message: {}", message);
|
||||||
|
}
|
||||||
|
} else if (message instanceof AckMessage) {
|
||||||
|
log.info("OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nameOf(UUID player) {
|
||||||
|
if (player == null) {
|
||||||
|
return "all players";
|
||||||
|
} else {
|
||||||
|
return players.get(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 85 B |
Loading…
Reference in New Issue