package game;
import interfaces.GameField;
import main.Main;
import model.UserProfile;
import utils.RandomUtils;
import websocket.GameWebSocketHandler;
import websocket.message.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* nickolay, 21.02.15.
*/
public class Room implements Comparable<Room> {
public static final int ROUND_NUMBER = 6;
private final long creationDate;
private final boolean isPrivate;
private final String id;
private static List<String> playerColors;
private int capacity;
private String name;
@Override
public int compareTo(Room o) {
return o.getId().compareTo(o.getId());
}
enum RoomState {
WAITING,
GAME
}
private Map<String, Player> players;
private UserProfile owner;
private RoomState roomState = RoomState.WAITING;
private GameField gameField;
private final GameService gameService;
private int currentRound = 0;
public Room(GameService gameService, UserProfile owner, int capcity, boolean isPrivate, String id, String name) {
this.players = new ConcurrentHashMap<>();
this.creationDate = System.currentTimeMillis();
this.gameService = gameService;
this.capacity = capcity;
this.isPrivate = isPrivate;
this.id = id;
this.owner = owner;
this.name = name;
this.playerColors = Main.mechanicsConfig.getStringList("snake.colors");
}
private int getPointsByDeathId(int deathId) {
return deathId;
}
public void onPlayerDeath(int playerId, int deathId) {
if (playerId >= players.size()) return;
int playerPoints = players.get(playerId).getPoints() + getPointsByDeathId(deathId);
players.get(playerId).setPoints(playerPoints);
broadcastMessage(new RatingUpdateMessage(this));
}
public void addPlayer(Player player) {
if (roomState != RoomState.WAITING) return;
players.put(player.getId(), player);
player.sendMessage(new RoomPlayersMessage(this));
broadcastMessage(new ConnectedPlayerMessage(player,
getPlayerIdByUser(player.getUserProfile())));
}
public void connect(GameWebSocketHandler handler) {
Player player = getPlayerByUser(handler.getUserProfile());
if (player != null) {
player.addConnection(handler);
handler.sendMessage(new RoomPlayersMessage(this));
} else {
String playerColor = getUnusedColor();
Player newPlayer = new Player(playerColor, handler.getUserProfile());
newPlayer.addConnection(handler);
addPlayer(newPlayer);
handler.setRoom(this);
}
}
public void onPlayerReady(Player player, boolean isReady) {
if (roomState != RoomState.WAITING) return;
player.setReady(isReady);
broadcastMessageExceptUser(
new ReadyMessage(player, isReady),
player.getUserProfile()
);
}
public void onKeyEvent(boolean isLeft, boolean isUp, int playerId) {
if (roomState != RoomState.GAME) return;
if (isLeft) {
if (isUp) {
gameField.doLeftUp(playerId);
} else {
gameField.doLeftDown(playerId);
}
} else {
if (isUp) {
gameField.doRightUp(playerId);
} else {
gameField.doRightDown(playerId);
}
}
}
public void startRound() {
System.out.println("[Room] startRound()");
if (currentRound < ROUND_NUMBER - 1) {
currentRound++;
for (int i = 0; i < players.size(); i++) {
players.get(i).sendMessage(new StartRoundMessage(this, i, currentRound, ROUND_NUMBER));
}
roomState = RoomState.GAME;
gameField = new GameFieldImpl(this, gameService);
gameField.play();
} else {
System.out.println("[Room] Конец игры! Раунды закончились");
endGame();
}
}
public void endGame() {
gameService.writePointsToDb(this);
broadcastMessage(new GameOverMessage(this));
if (gameField != null) {
gameField.pause();
}
gameService.destroyRoom(this);
}
public void startGame() {
if (roomState != RoomState.WAITING) return;
roomState = RoomState.GAME;
for (int i = 0; i < players.size(); i++) {
players.get(i).sendMessage(new StartGameMessage(this, i, currentRound, ROUND_NUMBER));
}
broadcastMessage(new RatingUpdateMessage(this));
gameField = new GameFieldImpl(this, gameService);
gameField.play();
}
public void onPlayerDisconnect(Player player) {
players.remove(player);
try {
broadcastMessageExceptUser(
new DisconnectedPlayerMessage(player),
player.getUserProfile()
);
} catch (Exception e) {
System.out.println("[Room] Disconnected player message sending error!");
}
if (players.size() == 0) {
System.out.println("[Room] Конец игры: 0 игроков, удаление комнаты!");
endGame();
}
}
public void broadcastMessage(Message message) {
for (Player player : players.values()) {
player.sendMessage(message);
}
}
public void broadcastMessageExceptUser(Message message, UserProfile user) {
for (Player player : players.values()) {
String roomUserId = player.getUserProfile().getId();
if (!roomUserId.equals(user.getId())) {
player.sendMessage(message);
}
}
}
public void broadcastMessageExceptConnection(Message message, GameWebSocketHandler connection) {
for (Player player : players.values()) {
player.sendMessageExceptConnection(message, connection);
}
}
public Player getPlayerByUser(UserProfile userProfile) {
for (Player player : players.values()) {
if (player.getUserProfile().getId().equals(userProfile.getId())) {
return player;
}
}
return null;
}
public int getPlayerIdByUser(UserProfile userProfile) {
int index = 0;
for (Player player : players.values()) {
if (player.getUserProfile().getId().equals(userProfile.getId())) {
return index;
}
index++;
}
return -1;
}
public boolean isColorUsed(String color) {
for (Player p : players.values()) {
if (p.getColor().equals(color)) {
return true;
}
}
return false;
}
public String getUnusedColor() {
for (String c : playerColors) {
if (!isColorUsed(c)) {
return c;
}
}
return "#000000";
}
public static String getRandomColor() {
return playerColors.get(RandomUtils.randInt(0, playerColors.size()));
}
public int getPlayerCount() {
return players.size();
}
public int getReadyPlayerCount() {
int readyUserCount = 0;
for (Player p : players.values()) {
if (p.isReady()) {
readyUserCount++;
}
}
return readyUserCount;
}
public void sendPatchToUser(UserProfile user, List<Integer> lostIds) {
getPlayerByUser(user).sendMessage(new SnakePatchMessage(gameField.getUpdatesManager().getListByIds(lostIds)));
}
public String getName() {
return name;
}
public Collection<Player> getPlayers() {
return players.values();
}
public RoomState getRoomState() {
return roomState;
}
public GameField getGameField() {
return gameField;
}
public long getCreationDate() {
return creationDate;
}
public int getCurrentRound() {
return currentRound;
}
public boolean isPrivate() {
return isPrivate;
}
public String getId() {
return id;
}
public UserProfile getOwner() {
return owner;
}
public int getCapacity() {
return capacity;
}
}