diff --git a/src/de/steamwar/lobby/LobbySystem.properties b/src/de/steamwar/lobby/LobbySystem.properties index 7fac647..cb49a38 100644 --- a/src/de/steamwar/lobby/LobbySystem.properties +++ b/src/de/steamwar/lobby/LobbySystem.properties @@ -137,6 +137,9 @@ JUMP_AND_RUN_PERSONAL_BEST_NO_TIME = §cNo personal best # Games GAMES_TICTACTOE = TicTacToe +GAMES_CONNECT_4 = Connect 4 + +GAMES_ALREADY_PRESENT = §cYou already have an open invitation GAMES_NO_SELF = §cYou can\'t play against yourself GAMES_CHALLENGED_BY = §e{0} §7challenged you to a game of §e{1} GAMES_CHALLENGED_BY_HOVER = §7Click to accept diff --git a/src/de/steamwar/lobby/LobbySystem_de.properties b/src/de/steamwar/lobby/LobbySystem_de.properties index 1258a30..c5172f9 100644 --- a/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/src/de/steamwar/lobby/LobbySystem_de.properties @@ -128,6 +128,9 @@ JUMP_AND_RUN_PERSONAL_BEST_NO_TIME = §cDu hast noch keinen Rekord # Games GAMES_TICTACTOE = TicTacToe +GAMES_CONNECT_4 = Vier Gewinnt + +GAMES_ALREADY_PRESENT = §cDu hast bereits eine Herausforderung! GAMES_NO_SELF = §cDu kannst dich nicht selbst herausfordern! GAMES_CHALLENGED_BY = §e{0} §7hat dich zu einem Spiel §e{1}§7 herausgefordert! GAMES_CHALLENGED_BY_HOVER = §7Klicke hier, um das Spiel zu bestätigen diff --git a/src/de/steamwar/lobby/games/Game.java b/src/de/steamwar/lobby/games/Game.java new file mode 100644 index 0000000..aadb81f --- /dev/null +++ b/src/de/steamwar/lobby/games/Game.java @@ -0,0 +1,30 @@ +package de.steamwar.lobby.games; + +import de.steamwar.lobby.LobbySystem; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; + +public abstract class Game implements Listener { + + @Getter + private final Player player; + + @Getter + private final Player opponent; + + protected Game(Player player, Player opponent) { + this.player = player; + this.opponent = opponent; + + Bukkit.getPluginManager().registerEvents(this, LobbySystem.getPlugin()); + } + + public abstract void start(); + + public void end() { + HandlerList.unregisterAll(this); + } +} diff --git a/src/de/steamwar/lobby/games/GameManager.java b/src/de/steamwar/lobby/games/GameManager.java new file mode 100644 index 0000000..4c5f204 --- /dev/null +++ b/src/de/steamwar/lobby/games/GameManager.java @@ -0,0 +1,62 @@ +package de.steamwar.lobby.games; + +import de.steamwar.lobby.LobbySystem; +import lombok.experimental.UtilityClass; +import net.md_5.bungee.api.chat.ClickEvent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.HashMap; +import java.util.Map; + +@UtilityClass +public class GameManager { + + private Map games = new HashMap<>(); + + private GameListener gameListener = new GameListener(); + + static { + Bukkit.getPluginManager().registerEvents(gameListener, LobbySystem.getPlugin()); + } + + private static class GameListener implements Listener { + + @EventHandler(ignoreCancelled = true) + public void onPlayerQuit(PlayerQuitEvent event) { + games.remove(event.getPlayer()); + games.values().removeIf(game -> game.getOpponent() == event.getPlayer()); + } + } + + public void registerGame(Games games, Player player, Player opponent) { + if (opponent == player) { + LobbySystem.getMessage().send("GAMES_NO_SELF", player); + return; + } + + if (GameManager.games.containsKey(opponent)) { + Game game = GameManager.games.get(opponent); + if (game.getOpponent() == player && games.isGame(game)) { + game.start(); + GameManager.games.remove(opponent); + GameManager.games.remove(player); + return; + } + } + + if (GameManager.games.containsKey(player)) { + LobbySystem.getMessage().send("GAMES_ALREADY_PRESENT", player); + return; + } + GameManager.games.put(player, games.createGame(player, opponent)); + LobbySystem.getMessage().send("GAMES_CHALLENGED_BY", opponent, LobbySystem.getMessage().parse("GAMES_CHALLENGED_BY_HOVER", opponent), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/games " + games.name() + " " + player.getName()), player.getName(), LobbySystem.getMessage().parse("GAMES_TICTACTOE", opponent)); + } + + public void unregisterGame(Player player) { + games.remove(player); + } +} diff --git a/src/de/steamwar/lobby/games/Games.java b/src/de/steamwar/lobby/games/Games.java new file mode 100644 index 0000000..1829738 --- /dev/null +++ b/src/de/steamwar/lobby/games/Games.java @@ -0,0 +1,49 @@ +package de.steamwar.lobby.games; + +import de.steamwar.lobby.games.tictactoe.TicTacToe; +import org.bukkit.entity.Player; + +public enum Games { + + TICTACTOE { + @Override + public String getName() { + return "GAMES_TICTACTOE"; + } + + @Override + public boolean isGame(Game game) { + return game instanceof TicTacToe; + } + + @Override + public Game createGame(Player player, Player opponent) { + return new TicTacToe(player, opponent); + } + }, + /* + CONNECT_4 { + @Override + public String getName() { + return "GAMES_CONNECT_4"; + } + + @Override + public boolean isGame(Game game) { + return game instanceof Connect4; + } + + @Override + public Game createGame(Player player, Player opponent) { + return new Connect4(player, opponent); + } + }, + */ + ; + + public abstract String getName(); + + public abstract boolean isGame(Game game); + + public abstract Game createGame(Player player, Player opponent); +} diff --git a/src/de/steamwar/lobby/games/GamesCommand.java b/src/de/steamwar/lobby/games/GamesCommand.java index c6e597d..4d7bed2 100644 --- a/src/de/steamwar/lobby/games/GamesCommand.java +++ b/src/de/steamwar/lobby/games/GamesCommand.java @@ -1,38 +1,21 @@ package de.steamwar.lobby.games; import de.steamwar.command.SWCommand; -import de.steamwar.lobby.LobbySystem; -import net.md_5.bungee.api.chat.ClickEvent; import org.bukkit.entity.Player; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class GamesCommand extends SWCommand { - private final Map> CHALLENGES = new HashMap<>(); - public GamesCommand() { super("games"); } - @Register("tictactoe") - public void tictactoe(Player player, Player target) { - if(player == target) { - LobbySystem.getMessage().send("GAMES_NO_SELF", player); - return; - } + @Register + public void game(Player player, Games games, Player opponent) { + GameManager.registerGame(games, player, opponent); + } - if(CHALLENGES.containsKey(player) && CHALLENGES.get(player).contains(target)) { - new TicTacToe(player, target).updateBoard(); - CHALLENGES.remove(player); - CHALLENGES.remove(target); - return; - } - - CHALLENGES.computeIfAbsent(target, k -> new ArrayList<>()).add(player); - LobbySystem.getMessage().send("GAMES_CHALLENGED_BY", target, LobbySystem.getMessage().parse("GAMES_CHALLENGED_BY_HOVER", target), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/games tictactoe " + player.getName()), player.getName(), LobbySystem.getMessage().parse("GAMES_TICTACTOE", target)); + @Register("stop") + public void stop(Player player) { + GameManager.unregisterGame(player); } } diff --git a/src/de/steamwar/lobby/games/Pair.java b/src/de/steamwar/lobby/games/Pair.java new file mode 100644 index 0000000..f9cf5e8 --- /dev/null +++ b/src/de/steamwar/lobby/games/Pair.java @@ -0,0 +1,15 @@ +package de.steamwar.lobby.games; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@AllArgsConstructor +@Getter +@ToString +@EqualsAndHashCode +public class Pair { + private A a; + private B b; +} diff --git a/src/de/steamwar/lobby/games/TicTacToe.java b/src/de/steamwar/lobby/games/TicTacToe.java deleted file mode 100644 index ecf847a..0000000 --- a/src/de/steamwar/lobby/games/TicTacToe.java +++ /dev/null @@ -1,153 +0,0 @@ -package de.steamwar.lobby.games; - -import de.steamwar.inventory.SWInventory; -import de.steamwar.inventory.SWItem; -import de.steamwar.lobby.LobbySystem; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.Random; - -public class TicTacToe implements Listener { - - private static final Random random = new Random(); - - private static final int[][] WINNING_COMBINATIONS = { - {0, 1, 2}, - {3, 4, 5}, - {6, 7, 8}, - {0, 3, 6}, - {1, 4, 7}, - {2, 5, 8}, - {0, 4, 8}, - {2, 4, 6} - }; - - private final Player player1; - private final Player player2; - private Player turn; - - private final int[] board = new int[9]; - - private int turns = 0; - - private boolean running = true; - - public TicTacToe(Player player1, Player player2) { - this.player1 = player1; - this.player2 = player2; - this.turn = random.nextBoolean() ? player1 : player2; - Bukkit.getPluginManager().registerEvents(this, LobbySystem.getPlugin()); - } - - public void updateBoard() { - for (int[] winningCombination : WINNING_COMBINATIONS) { - if(board[winningCombination[0]] == board[winningCombination[1]] && - board[winningCombination[1]] == board[winningCombination[2]] && - board[winningCombination[0]] != 0) { - win(turn, winningCombination); - return; - } - } - - if(turns++ == 9) { - draw(); - return; - } - - turn = turn == player1 ? player2 : player1; - showBoard(player1); - showBoard(player2); - } - - private void win(Player player, int[] winningCombination) { - running = false; - SWInventory inventory = createCurrentBoard(player1, LobbySystem.getMessage().parse("GAMES_WON", player1, player.getName())); - SWInventory inventory2 = createCurrentBoard(player2, LobbySystem.getMessage().parse("GAMES_WON", player2, player.getName())); - for (int j : winningCombination) { - inventory.setItem(j, new SWItem(Material.LIME_WOOL, "§" + j + "§a" + (board[j] == 1 ? "X" : "O"))); - inventory2.setItem(j, new SWItem(Material.LIME_WOOL, "§" + j + "§a" + (board[j] == 1 ? "X" : "O"))); - } - remake(inventory, inventory2); - inventory.open(); - inventory2.open(); - } - - private void draw() { - running = false; - SWInventory inventory = createCurrentBoard(player1, LobbySystem.getMessage().parse("GAMES_DRAW", player1)); - SWInventory inventory2 = createCurrentBoard(player2, LobbySystem.getMessage().parse("GAMES_DRAW", player2)); - remake(inventory, inventory2); - inventory.open(); - inventory2.open(); - } - - private void remake(SWInventory inventory, SWInventory inventory2) { - for (int i = 0; i < board.length; i++) { - inventory.setCallback(i, clickType -> player1.performCommand("games tictactoe " + player2.getName())); - inventory2.setCallback(i, clickType -> player2.performCommand("games tictactoe " + player1.getName())); - } - } - - private void end() { - running = false; - HandlerList.unregisterAll(this); - } - - private void showBoard(Player player) { - SWInventory inventory = createCurrentBoard(player, LobbySystem.getMessage().parse("GAMES_TURN", player, turn.getName())); - inventory.addCloseRunnable(() -> { - Bukkit.getScheduler().runTaskLater(LobbySystem.getPlugin(), () -> { - if(player.getOpenInventory().getTopInventory().getType() != InventoryType.DROPPER && running) { - player1.closeInventory(); - player2.closeInventory(); - LobbySystem.getMessage().send("GAMES_LEFT", player1, player.getName()); - LobbySystem.getMessage().send("GAMES_LEFT", player2, player.getName()); - end(); - } - }, 1); - }); - inventory.open(); - } - - private SWInventory createCurrentBoard(Player player, String title) { - SWInventory inventory = new SWInventory(player, () -> Bukkit.createInventory(null, InventoryType.DROPPER, title)); - for (int i = 0; i < board.length; i++) { - if(board[i] == 0) { - int finalI = i; - inventory.setItem(i, new SWItem(Material.LIGHT_GRAY_WOOL, "§" + i, clickType -> makeMove(player, finalI))); - } else { - inventory.setItem(i, new SWItem(board[i] == 1 ? Material.RED_WOOL : Material.BLUE_WOOL, "§" + i + "§" + (board[i] == 1? "c" : "3") + (board[i] == 1 ? "X" : "O"))); - } - } - return inventory; - } - - private void makeMove(Player player, int i) { - if(player != turn) { - return; - } - - if(board[i] != 0) { - return; - } - - board[i] = player == player1 ? 1 : 2; - updateBoard(); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - if(event.getPlayer() == player1 || event.getPlayer() == player2) { - player1.closeInventory(); - player2.closeInventory(); - end(); - } - } -} diff --git a/src/de/steamwar/lobby/games/connect4/Connect4.java b/src/de/steamwar/lobby/games/connect4/Connect4.java new file mode 100644 index 0000000..de495dd --- /dev/null +++ b/src/de/steamwar/lobby/games/connect4/Connect4.java @@ -0,0 +1,32 @@ +package de.steamwar.lobby.games.connect4; + +import de.steamwar.lobby.games.Game; +import org.bukkit.entity.Player; + +import java.util.Random; + +public class Connect4 extends Game { + + private static final Random RANDOM = new Random(); + + /** + * {@code false} means player, {@code true} means opponent + */ + private boolean turn = RANDOM.nextBoolean(); + + /** + * 0 = empty, 1 = player, 2 = opponent + */ + private final int[] board = new int[42]; + + private int turns = 0; + + public Connect4(Player player, Player opponent) { + super(player, opponent); + } + + @Override + public void start() { + + } +} diff --git a/src/de/steamwar/lobby/games/tictactoe/TicTacToe.java b/src/de/steamwar/lobby/games/tictactoe/TicTacToe.java new file mode 100644 index 0000000..2cdd0be --- /dev/null +++ b/src/de/steamwar/lobby/games/tictactoe/TicTacToe.java @@ -0,0 +1,122 @@ +package de.steamwar.lobby.games.tictactoe; + +import de.steamwar.inventory.SWInventory; +import de.steamwar.inventory.SWItem; +import de.steamwar.lobby.LobbySystem; +import de.steamwar.lobby.games.Game; +import de.steamwar.lobby.games.Pair; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; + +import java.util.Random; + +public class TicTacToe extends Game { + + private static final Random RANDOM = new Random(); + + private static final int[][] WINNING_COMBINATIONS = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {0, 3, 6}, {1, 4, 7}, {2, 5, 8}, {0, 4, 8}, {2, 4, 6}}; + + /** + * {@code false} means player, {@code true} means opponent + */ + private boolean turn = RANDOM.nextBoolean(); + + /** + * 0 = empty, 1 = player, 2 = opponent + */ + private final int[] board = new int[9]; + + private int turns = 0; + + public TicTacToe(Player player, Player opponent) { + super(player, opponent); + } + + private void showBoard(Player player) { + Pair winner = checkWin(); + boolean draw = turns == 9; + + String title; + if (winner != null) { + title = LobbySystem.getMessage().parse("GAMES_WON", player, winner.getA().getName()); + } else if (draw) { + title = LobbySystem.getMessage().parse("GAMES_DRAW", player); + } else { + title = LobbySystem.getMessage().parse("GAMES_TURN", player, (turn ? getOpponent() : getPlayer()).getName()); + } + + SWInventory inventory = new SWInventory(player, () -> Bukkit.createInventory(null, InventoryType.DROPPER, title)); + for (int i = 0; i < 9; i++) { + if (board[i] == 0) { + int finalI = i; + if (winner != null) { + inventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§" + i)); + } else { + inventory.setItem(i, new SWItem(Material.LIGHT_GRAY_WOOL, "§" + i, clickType -> { + if (turn == (player == getPlayer())) return; + + board[finalI] = turn ? 2 : 1; + turn = !turn; + turns++; + showBoard(getPlayer()); + showBoard(getOpponent()); + })); + } + } else if (board[i] == 1) { + inventory.setItem(i, new SWItem((winner == null || contains(winner.getB(), i)) ? Material.RED_WOOL : Material.RED_STAINED_GLASS_PANE, "§" + i + "§cX")); + } else { + inventory.setItem(i, new SWItem((winner == null || contains(winner.getB(), i)) ? Material.BLUE_WOOL : Material.BLUE_STAINED_GLASS_PANE, "§" + i + "§bO")); + } + } + + // Remake + if (winner != null || draw) { + for (int i = 0; i < board.length; i++) { + inventory.setCallback(i, clickType -> { + player.performCommand("games tictactoe " + getOpponent().getName()); + player.getOpenInventory().close(); + }); + } + } + + inventory.addCloseRunnable(() -> { + Bukkit.getScheduler().runTaskLater(LobbySystem.getPlugin(), () -> { + if (getOpponent().getOpenInventory().getTopInventory().getType() != InventoryType.DROPPER) { + return; + } + if (player.getOpenInventory().getTopInventory().getType() != InventoryType.DROPPER) { + getPlayer().closeInventory(); + getOpponent().closeInventory(); + LobbySystem.getMessage().send("GAMES_LEFT", getPlayer(), player.getName()); + LobbySystem.getMessage().send("GAMES_LEFT", getOpponent(), player.getName()); + end(); + } + }, 1); + }); + inventory.open(); + } + + private boolean contains(int[] ints, int i) { + for (int anInt : ints) { + if (anInt == i) return true; + } + return false; + } + + private Pair checkWin() { + for (int[] winningCombination : WINNING_COMBINATIONS) { + if (board[winningCombination[0]] == board[winningCombination[1]] && board[winningCombination[1]] == board[winningCombination[2]] && board[winningCombination[0]] != 0) { + return new Pair<>(board[winningCombination[0]] == 1 ? getPlayer() : getOpponent(), winningCombination); + } + } + return null; + } + + @Override + public void start() { + showBoard(getPlayer()); + showBoard(getOpponent()); + } +}