package nl.sugcube.crystalquest.game; import nl.sugcube.crystalquest.Broadcast; import nl.sugcube.crystalquest.CrystalQuest; import nl.sugcube.crystalquest.events.ArenaStartEvent; import nl.sugcube.crystalquest.events.PlayerJoinArenaEvent; import nl.sugcube.crystalquest.events.PlayerLeaveArenaEvent; import nl.sugcube.crystalquest.events.TeamWinGameEvent; import nl.sugcube.crystalquest.sba.SMeth; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.*; import org.bukkit.inventory.Inventory; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scoreboard.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * @author SugarCaney */ public class Arena { /** * The main plugin instance. */ public CrystalQuest plugin; /** * The maximum amount of players in the arenas. * <p> * {@code -1} when this value is not set. */ private int maxPlayers = -1; /** * The minimum amount of players in the arenas. * <p> * {@code -1} when this value is not set. */ private int minPlayers = -1; /** * The name of the arenas. * <p> * {@code ""} when there is no name set. */ private String name = ""; /** * The unique id of the arenas. */ private int id; /** * Determines if the crystalquest.vip permission is required in order to play in the arenas. * <p> * {@code true} when required, {@code false} when not required. */ private boolean vip; /** * Map that stores per team what the spawn location is for the lobby. */ private Map<CrystalQuestTeam, Location> lobbySpawns = new HashMap<>(); /** * The amount of seconds it takes before the arenas starts. */ private int count; /** * Determines whether the countdown is doing its buisiness. * <p> * {@code true} when the countdown is happening, {@code false} when there is no countdown. */ private boolean isCounting; /** * The scoreboard tracking the scores of the teams. */ private Scoreboard score; /** * Contains whether the arenas is in game or not. * <p> * {@code true} when the arenas is ingame, {@code false} otherwise. */ private boolean inGame; /** * The amount of seconds that is left in the game. */ private int timeLeft; /** * Whether the arenas is enabled or disabled. * <p> * {@code true} when the arenas is enabled, {@code false} when disabled. */ private boolean enabled = true; /** * The amount of seconds that is left in the resetting phase. */ private int afterCount; /** * Whether the game is over and is resetting or not. * <p> * {@code true} when the arenas is resetting, {@code false} otherwise. */ private boolean isEndGame = false; /** * The two corner positions of the arenas that define the protection. */ private Location[] protection = new Location[2]; /** * Whether double jump is enabled in this arenas or not. * <p> * {@code true} when there is double jump, {@code false} when there is no double jump. */ private boolean doubleJump = false; /** * Random object to be used by this instance. */ private Random ran = new Random(); /** * List of all the places where players will spawn. */ private List<Location> playerSpawns = new ArrayList<>(); /** * List of all the places where crystal will spawn. */ private List<Location> crystalSpawns = new ArrayList<>(); /** * List of all the locations where items will spawn. */ private List<Location> itemSpawns = new ArrayList<>(); /** * List of all the wolfs that have been spawned in the arenas. */ private List<Wolf> gameWolfs = new ArrayList<>(); /** * List of all creepers that have been spawned in the arenas. */ private List<Creeper> gameCreepers = new ArrayList<>(); /** * List of all crystals that have been spawned in the arenas. */ private List<Entity> gameCrystals = new ArrayList<>(); /** * List of all UUIDs of players that are in the arenas. */ private List<UUID> players = new ArrayList<>(); /** * List of all UUIDs of players that are spectating the arenas. */ private List<UUID> spectators = new ArrayList<>(); /** * Map that maps every player's UUID to the team which they are part of. */ private Map<UUID, CrystalQuestTeam> playerTeams = new ConcurrentHashMap<>(); /** * Map that maps every ender crystal to their location. */ private Map<Entity, Location> crystalLocations = new ConcurrentHashMap<>(); /** * List of all blocks that are placed during the game in the arenas. */ private List<Block> gameBlocks = new ArrayList<>(); /** * Map that maps the team to a list of all locations where their players can spawn. */ private Map<CrystalQuestTeam, List<Location>> teamSpawns = new ConcurrentHashMap<>(); /** * Map that maps all locations of placed landmines to the UUID of the player that placed it. */ private Map<Location, UUID> landmines = new ConcurrentHashMap<>(); /** * Map that maps the UUID of a player to the gamemode which they had before entering the arenas. */ private Map<UUID, GameMode> preSpecGamemodes = new ConcurrentHashMap<>(); /** * The menu that shows up when players want to select a team when joining the arenas. */ private Inventory teamMenu; /** * List containing all the teams that are available for the arena. */ private List<CrystalQuestTeam> teams = new ArrayList<>(); //Scoreboard /** * Scoreboard: Maps each CrystalQuest team to a respective scoreboard team. */ private Map<CrystalQuestTeam, Team> scoreboardTeams = new ConcurrentHashMap<>(); /** * Scoreboard: The object used to track the points earned. */ private Objective points; /** * Scoreboard: Maps CrystalQuest teams to their respective scoreboard scores. */ private Map<CrystalQuestTeam, Score> scoreboardScores = new ConcurrentHashMap<>(); /** * Scoreboard: Team that contains all the spectators. */ private Team spectatorTeam; /** * @param instance * Instance of the plugin * @param arenaId * ID of the arenas */ public Arena(CrystalQuest instance, int arenaId) { this.plugin = instance; this.score = Bukkit.getScoreboardManager().getNewScoreboard(); this.timeLeft = plugin.getConfig().getInt("arena.game-length"); this.count = plugin.getConfig().getInt("arena.countdown"); this.id = arenaId; this.afterCount = plugin.getConfig().getInt("arena.after-count"); for (CrystalQuestTeam team : CrystalQuestTeam.getTeams()) { teamSpawns.put(team, new ArrayList<>()); } initializeScoreboard(); } /** * Get a list of UUIDs of players who are spectating the game. * * @see Arena#spectators */ public List<UUID> getSpectators() { return spectators; } /** * Get the map containing the players who placed certain landmines. * * @see Arena#landmines */ public Map<Location, UUID> getLandmines() { return this.landmines; } /** * Sets if the arenas accepts double jumps * * @param canDoubleJump * True to accept, False to decline. * @see Arena#doubleJump */ public void setDoubleJump(boolean canDoubleJump) { this.doubleJump = canDoubleJump; } /** * Gets if this map accepts double jumps * * @return True if accepted, false if not accepted. * @see Arena#doubleJump */ public boolean canDoubleJump() { return doubleJump; } /** * Gets the hashmap with the crystalquest team mapped to the list containing the spawnpoints * * @see Arena#teamSpawns */ public Map<CrystalQuestTeam, List<Location>> getTeamSpawns() { return teamSpawns; } /** * Get all the teamspawns of a given team. * * @param team * The team to get the spawns of. * @return The teamspawns, or {@code null} when there are no team spawns. */ public List<Location> getTeamSpawns(CrystalQuestTeam team) { return teamSpawns.get(team); } /** * Sets the positions of the protection of the Arena * * @param locs * Index 0: pos1, Index 1: pos2. * @see Arena#protection */ public void setProtection(Location[] locs) { this.protection = locs; } /** * Gets the positions of the protection of the Arena * * @return Index 0: pos1, Index 2: pos0. Null if not set. * @see Arena#protection */ public Location[] getProtection() { return protection; } /** * Checks if the arenas is full * * @return True if full, False if not. */ public boolean isFull() { return getPlayers().size() >= getMaxPlayers(); } /** * Gets the Wolf-list containing all Wolfs spawned in-game * * @see Arena#gameWolfs */ public List<Wolf> getGameWolfs() { return gameWolfs; } /** * Gets the Blocks-list containing all blocks placed in-game * * @see Arena#gameBlocks */ public List<Block> getGameBlocks() { return gameBlocks; } /** * Gets the Creepers which are spawned in-game * * @return List containing all the creepers * @see Arena#gameCreepers */ public List<Creeper> getGameCreepers() { return gameCreepers; } /** * Gets the inventory of the Team-Menu * * @return The team-menu inventory * @see Arena#teamMenu */ public Inventory getTeamMenu() { return teamMenu; } /** * Get the hashmap containing the locations of the entities * * @return EnderCrystals and Locations * @see Arena#crystalLocations */ public Map<Entity, Location> getCrystalLocations() { return crystalLocations; } /** * Checks whether a player with the given id is player or spectator in the arenas. * * @param uuid * The uuid of the player. * @return {@code true} when the player is in the arenas, {@code false} otherwise. */ public boolean isInArena(UUID uuid) { return players.contains(uuid) || spectators.contains(uuid); } /** * Checks whether a player is in the arenas (spectator or playing). * * @param player * The player to check for. * @return {@code true} when the player is in the arenas, {@code false} otherwise. */ public boolean isInArena(Player player) { return isInArena(player.getUniqueId()); } /** * Sends a custom message to all players in the arenas * * @param player * The dead player * @param message * The verb that will show up. fe: Killed, Gibbed etc. */ public void sendDeathMessage(Player player, String message) { CrystalQuestTeam team = plugin.getArenaManager().getTeam(player); ChatColor colour = team.getChatColour(); for (UUID id : getPlayers()) { Player target = Bukkit.getPlayer(id); target.sendMessage(colour + player.getName() + ChatColor.GRAY + message); } for (UUID id : getSpectators()) { Player target = Bukkit.getPlayer(id); target.sendMessage(colour + player.getName() + ChatColor.GRAY + message); } } /** * Sends a death message to all players in the arenas with a custom verb * * @param dead * The dead player * @param killer * The player who killed dead * @param verb * The verb that will show up. fe: Killed, Gibbed etc. */ public void sendDeathMessage(Player dead, Player killer, String verb) { CrystalQuestTeam team = plugin.getArenaManager().getTeam(dead); CrystalQuestTeam teamKiller = plugin.getArenaManager().getTeam(killer); ChatColor c = team.getChatColour(); ChatColor cK = teamKiller.getChatColour(); for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); player.sendMessage(c + dead.getName() + ChatColor.GRAY + " has been " + verb + " by " + cK + killer.getName()); } for (UUID id : getSpectators()) { Player spectator = Bukkit.getPlayer(id); spectator.sendMessage(c + dead.getName() + ChatColor.GRAY + " has been " + verb + " by " + cK + killer.getName()); } } /** * Sends a death message to all players in the arenas * * @param dead * The dead player * @param killer * The player who killed dead */ public void sendDeathMessage(Player dead, Player killer) { CrystalQuestTeam team = plugin.getArenaManager().getTeam(dead); CrystalQuestTeam teamKiller = plugin.getArenaManager().getTeam(killer); ChatColor c = team.getChatColour(); ChatColor cK = teamKiller.getChatColour(); for (UUID id : getPlayers()) { Player pl = Bukkit.getPlayer(id); pl.sendMessage(c + dead.getName() + ChatColor.GRAY + " has been killed by " + cK + killer.getName()); } for (UUID id : getSpectators()) { Player spec = Bukkit.getPlayer(id); spec.sendMessage(c + dead.getName() + ChatColor.GRAY + " has been killed by " + cK + killer.getName()); } } /** * Sends a death message to all players in the arenas * * @param player * The dead player */ public void sendDeathMessage(Player player) { CrystalQuestTeam team = plugin.getArenaManager().getTeam(player); ChatColor c = team.getChatColour(); for (UUID id : getPlayers()) { Player pl = Bukkit.getPlayer(id); pl.sendMessage(c + player.getName() + ChatColor.GRAY + " has died"); } for (UUID id : getSpectators()) { Player spec = Bukkit.getPlayer(id); spec.sendMessage(c + player.getName() + ChatColor.GRAY + " has died"); } } /** * Get the list containing all the crystals that have spawned in the arenas * * @return The crystals * @see Arena#gameCrystals */ public List<Entity> getGameCrystals() { return gameCrystals; } /** * Gets the time the game waits before teleporting to the lobby, after the game ended. * * @return The amount of seconds left. * @see Arena#afterCount */ public int getAfterCount() { return afterCount; } /** * Sets the time the game waits before teleporting to the lobby, after the game ended. * * @param count * The amount of seconds to wait * @see Arena#afterCount */ public void setAfterCount(int count) { this.afterCount = count; } /** * Returns true if the game has finished and is in the after-game phase. * * @return true if the game has ended, false if it hasn't * @see Arena#isEndGame */ public boolean isEndGame() { return isEndGame; } /** * Sets the the arenas is in the end-game phase * * @param isEndGame * true if end-game, false if isn't. * @see Arena#isEndGame */ public void setEndGame(boolean isEndGame) { if (isEndGame) { for (Entity e : this.getGameCrystals()) { getCrystalLocations().remove(e); e.remove(); } setAfterCount(plugin.getConfig().getInt("arena.after-count")); } this.isEndGame = isEndGame; plugin.signHandler.updateSigns(); } /** * Get the teams (scoreboard) in the arenas * * @return The teams in the arenas */ public Collection<Team> getScoreboardTeams() { return scoreboardTeams.values(); } /** * Checks if the arenas is enabled/disabled. * * @return If enabled true, if disabled false * @see Arena#enabled */ public boolean isEnabled() { return enabled; } /** * Sets the state of the arenas. * * @param isEnabled * "true" to enable, "false" to disable * @see Arena#enabled */ public void setEnabled(boolean isEnabled) { this.enabled = isEnabled; for (UUID id : this.getPlayers()) { Player player = Bukkit.getPlayer(id); player.sendMessage(Broadcast.get("arena.disabled")); } if (!isEnabled) { resetArena(false); } plugin.signHandler.updateSigns(); } /** * Updates the time in the scoreboardname */ public void updateTimer() { this.points.setDisplayName( SMeth.setColours( "&c" + Broadcast.get("arena.time-left") + " &f" + SMeth.toTime(timeLeft) ) ); } /** * Sets the menu from which the players choose their teams. * * @param teamMenu * Inventory to set it to. * @see Arena#teamMenu */ public void setTeamMenu(Inventory teamMenu) { this.teamMenu = teamMenu; } /** * Gets the teams with the least amount of players for a fair distribution process. * * @return The teams with the least amount of players. */ public List<CrystalQuestTeam> getSmallestTeams() { if (getScoreboardTeams().isEmpty()) { return new ArrayList<>(); } int leastAmount = getScoreboardTeams().stream() .min((t, u) -> Integer.valueOf(t.getSize()).compareTo(u.getSize())) .map(Team::getSize) .orElseThrow(() -> new IllegalStateException("There is no minimum")); return scoreboardTeams.entrySet().stream() .filter(entry -> entry.getValue().getEntries().size() <= leastAmount) .map(Map.Entry::getKey) .collect(Collectors.toList()); } /** * Initializes the scoreboard. This makes or updates the scoreboard. */ public void initializeScoreboard() { score = Bukkit.getScoreboardManager().getNewScoreboard(); scoreboardTeams.clear(); scoreboardScores.clear(); spectatorTeam = score.registerNewTeam("Spectate"); spectatorTeam.setAllowFriendlyFire(false); spectatorTeam.setCanSeeFriendlyInvisibles(true); spectatorTeam.setPrefix(ChatColor.BLUE + "[Spec] "); for (CrystalQuestTeam cqTeam : getTeams()) { Team team = score.registerNewTeam(cqTeam.getName()); team.setPrefix(cqTeam.getChatColour().toString()); team.setAllowFriendlyFire(false); scoreboardTeams.put(cqTeam, team); } points = score.registerNewObjective("points", "dummy"); points.setDisplaySlot(DisplaySlot.SIDEBAR); updateTimer(); for (CrystalQuestTeam cqTeam : getTeams()) { Score score = points.getScore(cqTeam.toString()); score.setScore(0); scoreboardScores.put(cqTeam, score); } } /** * Gets the amount of players in a team. * * @param team * The team to get the amount of players from. * @return The amount of players. */ public int getTeamPlayerCount(CrystalQuestTeam team) { return (int)playerTeams.entrySet().stream() .filter(entry -> entry.getValue().equals(team)) .count(); } /** * Gets the team the player is in. * * @param player * The player from whose you want to know the team he/she is in. * @return The team the player is in. */ public CrystalQuestTeam getTeam(Player player) { return playerTeams.get(player.getUniqueId()); } /** * Get an unmodifiable collection containing all the teams that are present in the arena. */ public Collection<CrystalQuestTeam> getTeams() { return Collections.unmodifiableList(teams); } /** * Checks if the given team participates in the arena. * * @param team * The team to check for. * @return {@code true} if the team participates, {@code false} otherwise. */ public boolean hasTeam(CrystalQuestTeam team) { return teams.contains(team); } /** * Checks if the player is in the specific team. * * @param player * The player you want to check for. * @param team * The team constant. * @return true if they're in, false if they aren't. */ public boolean isInTeam(Player player, CrystalQuestTeam team) { return team.equals(playerTeams.get(player.getUniqueId())); } /** * If there are players in the arenas * Reveal the winner * * @return The winning team, or {@code null} when something went wrong. */ public CrystalQuestTeam declareWinner() { if (getPlayers().isEmpty()) { return null; } Score hScore = scoreboardScores.values().stream() .max((s, t) -> Integer.valueOf(s.getScore()).compareTo(t.getScore())) .orElseThrow(() -> new AssertionError("Should not happen!")); CrystalQuestTeam winningTeam = null; List<UUID> winningPlayers = new ArrayList<>(); for (CrystalQuestTeam cqTeam : getTeams()) { if (hScore.getPlayer().getName().equalsIgnoreCase(cqTeam.toString())) { winningTeam = cqTeam; } } if (winningTeam == null) { throw new IllegalStateException("Winning team could not be found!"); } ChatColor colour = winningTeam.getChatColour(); for (UUID id : getPlayers()) { Player p = Bukkit.getPlayer(id); p.sendMessage(colour + "<>---------------------------<>"); p.sendMessage(" " + winningTeam + " " + Broadcast.get("arena.won")); p.sendMessage(colour + "<>---------------------------<>"); if (plugin.am.getTeam(p).equals(winningTeam)) { winningPlayers.add(p.getUniqueId()); } } Bukkit.getPluginManager().callEvent( new TeamWinGameEvent( winningPlayers, this, winningTeam, getTeamCount(), scoreboardTeams.values() ) ); return winningTeam; } /** * Chooses a random player in the arenas and from another team. * * @param excluded * The player whose team cannot be chosen. * @return The chosen player. Null if there are no players to choose from. */ public Player getRandomPlayer(Player excluded) { CrystalQuestTeam team = getTeam(excluded); List<Player> toChoose = new ArrayList<>(); for (UUID id : players) { Player player = Bukkit.getPlayer(id); if (!getTeam(player).equals(team)) { toChoose.add(player); } } if (toChoose.size() == 0) { return null; } return toChoose.get(ran.nextInt(toChoose.size())); } /** * Resets Arena-properties to default. Containing: * Countdown, * Game-time, * Removes the players, * Re-initializes scoreboard. * Sends a "this-team-won" message * * @param onEnable * (boolean) If it's called in onEnable. */ public void resetArena(boolean onEnable) { if (!onEnable) { //Removes all potion-effects on players if (getPlayers().size() > 0) { for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); Collection<PotionEffect> effects = player.getActivePotionEffects(); for (PotionEffect effect : effects) { player.removePotionEffect(effect.getType()); } plugin.itemHandler.cursed.remove(player); } } //Removes all blocks placed in-game if (getGameBlocks().size() > 0) { List<Block> toRemove = new ArrayList<>(); toRemove.addAll(getGameBlocks()); for (Location location : getLandmines().keySet()) { toRemove.add(location.getBlock()); } for (Block block : toRemove) { block.setType(Material.AIR); } } //Removs all wolfs if (getGameWolfs().size() > 0) { for (Wolf wolf : getGameWolfs()) { if (wolf != null) { wolf.setHealth(0); } } } //Removes all items and crystals if (getCrystalSpawns().size() > 0) { List<Entity> toRemove = new ArrayList<>(); for (Entity e : getCrystalSpawns().get(0).getWorld().getEntities()) { if ((e instanceof Item || e instanceof ExperienceOrb || e instanceof Arrow || e instanceof EnderCrystal || e instanceof LivingEntity) && !(e instanceof Player)) { if (plugin.prot.isInProtectedArena(e.getLocation())) { toRemove.add(e); } } } for (Entity entity : toRemove) { entity.remove(); } } } gameCrystals.clear(); count = plugin.getConfig().getInt("arena.countdown"); isCounting = false; timeLeft = this.plugin.getConfig().getInt("arena.game-length"); inGame = false; afterCount = plugin.getConfig().getInt("arena.after-game"); isEndGame = false; crystalLocations.clear(); gameBlocks.clear(); initializeScoreboard(); gameWolfs.clear(); landmines.clear(); removePlayers(); plugin.signHandler.updateSigns(); } /** * Get the scoreboard of the arenas. * * @return Scoreboard of the arenas * @see Arena#score */ public Scoreboard getScoreboard() { return score; } /** * Removes a player from the arenas including removal from the team, * resetting his/her scoreboard and restoring his/her inventory. * * @param p * The player you want to remove from the arenas. */ public void removePlayer(Player p) { if (!spectators.contains(p.getUniqueId())) { for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); player.sendMessage(Broadcast.TAG + Broadcast.get("arena.leave") .replace("%player%", getTeam(p).getChatColour() + p.getName()) .replace("%count%", "(" + (getPlayers().size() - 1) + "/" + getMaxPlayers() + ")")); } } players.remove(p.getUniqueId()); for (Team team : scoreboardTeams.values()) { if (team.hasPlayer((OfflinePlayer)p)) { team.removePlayer((OfflinePlayer)p); } } for (PotionEffect potionEffect : p.getActivePotionEffects()) { p.removePotionEffect(potionEffect.getType()); } try { p.teleport(plugin.am.getLobby()); } catch (Exception e) { plugin.getLogger().info("Lobby-spawn not set!"); } p.removePotionEffect(PotionEffectType.INVISIBILITY); try { p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); } catch (IllegalArgumentException ignored) { // Somehow, p.isInvalid() does not work on this. This will do :/ } playerTeams.remove(p.getUniqueId()); plugin.im.restoreInventory(p); plugin.im.playerClass.remove(p.getUniqueId()); spectators.remove(p.getUniqueId()); if (p.getGameMode() != GameMode.CREATIVE) { p.setAllowFlight(false); } plugin.ab.getAbilities().remove(p.getUniqueId()); p.setFireTicks(0); Bukkit.getPluginManager().callEvent(new PlayerLeaveArenaEvent(p, this)); if (spectatorTeam.getPlayers().contains(p)) { spectatorTeam.removePlayer(p); } plugin.signHandler.updateSigns(); } /** * Adds a player to the arenas including putting into a team, set the * scoreboard and give the in-game inventory. * * @param p * The player to add * @param team * The team to put the player in * @param spectate * True if the player is spectating * @return True if joined, False if not joined */ public boolean addPlayer(Player p, CrystalQuestTeam team, boolean spectate) { PlayerJoinArenaEvent event = new PlayerJoinArenaEvent(p, this, spectate); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled()) { if (!isFull() || plugin.getArenaManager().getArena(p.getUniqueId()).getSpectators() .contains(p.getUniqueId())) { if (isEnabled()) { try { if (!spectate) { playerTeams.put(p.getUniqueId(), team); } if (!spectate) { players.add(p.getUniqueId()); getTeamObject(team).addPlayer((OfflinePlayer)p); } p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); p.setScoreboard(this.score); plugin.im.setInGameInventory(p); if (spectate) { preSpecGamemodes.put(p.getUniqueId(), p.getGameMode()); p.setGameMode(GameMode.SPECTATOR); p.setAllowFlight(true); getSpectators().add(p.getUniqueId()); p.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 127)); p.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, Integer.MAX_VALUE, 127)); p.addPotionEffect(new PotionEffect(PotionEffectType.SLOW_DIGGING, Integer.MAX_VALUE, 127)); p.sendMessage(Broadcast.TAG + Broadcast.get("arena.spectate") .replace("%arena%", this.getName())); spectatorTeam.addPlayer(p); } if (!spectate) { Location lobby = getLobbySpawn(team); if (lobby == null) { p.teleport(lobbySpawns.values().iterator().next()); } else { p.teleport(lobby); } } else { if (getPlayerSpawns().size() > 0) { p.teleport(getPlayerSpawns().get(0)); } else { p.teleport(getTeamSpawns().values().iterator().next().get(0)); } } plugin.menuPT.updateMenu(this); if (!spectate) { for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); player.sendMessage(Broadcast.TAG + Broadcast.get("arena.join") .replace("%player%", team.getChatColour() + p.getName()) .replace("%count%", "(" + getPlayers().size() + "/" + getMaxPlayers() + ")")); } } plugin.signHandler.updateSigns(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } else { p.sendMessage(Broadcast.get("arena.disabled")); } } else { p.sendMessage(Broadcast.get("arena.full")); } } return false; } /** * Removes ALL players from the arenas and resets their inventory etc. */ public void removePlayers() { for (UUID id : players) { Player player = Bukkit.getPlayer(id); try { player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); plugin.im.restoreInventory(player); try { player.teleport(plugin.am.getLobby()); } catch (Exception e) { plugin.getLogger().info("Lobby-spawn not set!"); } } catch (Exception ignored) { } } players.clear(); for (UUID id : getSpectators()) { Player player = Bukkit.getPlayer(id); try { player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); plugin.im.restoreInventory(player); player.setGameMode(preSpecGamemodes.get(player.getUniqueId())); preSpecGamemodes.remove(player.getUniqueId()); try { player.teleport(plugin.am.getLobby()); } catch (Exception e) { plugin.getLogger().info("Lobby-spawn not set!"); } finally { player.removePotionEffect(PotionEffectType.INVISIBILITY); player.removePotionEffect(PotionEffectType.WEAKNESS); player.removePotionEffect(PotionEffectType.SLOW_DIGGING); } } catch (Exception ignored) { } } spectators.clear(); for (Team team : scoreboardTeams.values()) { for (OfflinePlayer op : team.getPlayers()) { team.removePlayer(op); } } } /** * Gets a list of all players currently in the arenas. * * @return The players in the arenas * @see Arena#players */ public List<UUID> getPlayers() { return players; } /** * Removes all possible Item-spawnpoints from the arenas */ public void clearItemSpawns() { itemSpawns.clear(); } /** * Removes a specific Item-spawnpoint from the arenas * * @param loc * The spawnpoint-location you'd like to remove */ public void removeItemSpawn(Location loc) { itemSpawns.remove(loc); } /** * Removes a specific Item-spawnpoint from the arenas * * @param index * The spawnpoint-index you'd like to remove */ public void removeItemSpawn(int index) { itemSpawns.remove(index); } /** * Adds an Item-spawnpoint to the arenas * * @param loc * The spawnpoint-location you'd like to add */ public void addItemSpawn(Location loc) { itemSpawns.add(loc); } /** * Sets all the Item-spawns for this arenas * * @param spawns * All spawn-locations */ public void setItemSpawns(List<Location> spawns) { itemSpawns = spawns; } /** * Sets all the Item-spawns for this arenas * * @param spawns * All spawn-locations */ public void setItemSpawns(Location[] spawns) { itemSpawns.clear(); Collections.addAll(itemSpawns, spawns); } /** * Get a list containing all the Item-spawn locations * * @return All the item-spawn locations * @see Arena#itemSpawns */ public List<Location> getItemSpawns() { return itemSpawns; } /** * Removes all crystal-spawns from the arenas * * @see Arena#crystalSpawns */ public void clearCrystalSpawns() { crystalSpawns.clear(); } /** * Remove a specific crystal-spawn location * * @param loc * The location you'd like to remove * @see Arena#crystalSpawns */ public void removeCrystalSpawn(Location loc) { crystalSpawns.remove(loc); } /** * Remove a specific crystal-spawn location * * @param index * The index in the location-list * @see Arena#crystalSpawns */ public void removeCrystalSpawn(int index) { crystalSpawns.remove(index); } /** * Add a crystal spawn. * * @param loc * The location you want to add * @see Arena#crystalSpawns */ public void addCrystalSpawn(Location loc) { crystalSpawns.add(loc); } /** * Set the crystal Spawns from a list * * @param spawns * List containing all the spawnpoints * @see Arena#crystalSpawns */ public void setCrystalSpawns(List<Location> spawns) { crystalSpawns = spawns; } /** * Set the crystal Spawns from an array * * @param spawns * Array containing all the spawnpoints * @see Arena#crystalSpawns */ public void setCrystalSpawns(Location[] spawns) { crystalSpawns.clear(); Collections.addAll(crystalSpawns, spawns); } /** * Get the crystal spawns. * * @return List containing all the crystal-spawn locations * @see Arena#crystalSpawns */ public List<Location> getCrystalSpawns() { return crystalSpawns; } /** * Clear playerSpawns. * * @see Arena#playerSpawns */ public void clearPlayerSpawns() { playerSpawns.clear(); } /** * Remove a player spawn. * * @param loc * Location to remove. * @see Arena#playerSpawns */ public void removePlayerSpawn(Location loc) { if (playerSpawns.contains(loc)) { playerSpawns.remove(loc); } } /** * Remove a player spawn. * * @param index * Location to remove (index). * @see Arena#playerSpawns */ public void removePlayerSpawn(int index) { playerSpawns.remove(index); } /** * Add a player spawn. * * @param loc * A new Player-spawnpoint * @see Arena#playerSpawns */ public void addPlayerSpawn(Location loc) { playerSpawns.add(loc); } /** * Set the player Spawns * * @param spawns * A list containing all the player-spawns. * @see Arena#playerSpawns */ public void setPlayerSpawns(List<Location> spawns) { playerSpawns = spawns; } /** * Set the player Spawns * * @param spawns * An array containing all the player-spawns. * @see Arena#playerSpawns */ public void setPlayerSpawns(Location[] spawns) { playerSpawns.clear(); Collections.addAll(playerSpawns, spawns); } /** * Get the player spawns. * * @return A list containing all the player-spawnpoints * @see Arena#playerSpawns */ public List<Location> getPlayerSpawns() { return playerSpawns; } /** * Set the time left in the game. * * @param timeInSeconds * The time in seconds the game will last * @see Arena#timeLeft */ public void setTimeLeft(int timeInSeconds) { timeLeft = timeInSeconds; } /** * Get the time left in the arenas. * * @return The time left in seconds * @see Arena#timeLeft */ public int getTimeLeft() { return timeLeft; } /** * Checks if the arenas is in-game. * * @return true if in-game, false if not in-game. * @see Arena#inGame */ public boolean isInGame() { return inGame; } /** * Set the in-game status of the game. * * @see Arena#inGame */ public void setInGame(boolean inGame) { this.inGame = inGame; } /** * Get if the countdown is happening. * * @return True if the countdown has started. False if not. * @see Arena#isCounting */ public boolean isCounting() { return isCounting; } /** * Set if countdown is happening. * * @see Arena#isCounting */ public void setIsCounting(boolean isCountingB) { isCounting = isCountingB; plugin.signHandler.updateSigns(); } /** * Set the countdown. * * @param seconds * The amount of seconds to set the countdown to (-1 for default countdown). * @see Arena#count */ public void setCountdown(int seconds) { this.count = seconds; } /** * Get the amount of seconds left. * * @return Seconds left. * @see Arena#count */ public int getCountdown() { return count; } /** * Set where the lobbyspawn is of a certain team. * * @param team * The team to set the lobby spawn of. * @param location * The location of the lobby spawn. */ public void setLobbySpawn(CrystalQuestTeam team, Location location) { if (location == null) { lobbySpawns.remove(team); } lobbySpawns.put(team, location); } /** * Gets the team-lobby spawn of a certain team. * * @param team * The team to get the lobby spawn of. * @return The lobby spawn of the team, or {@code null} when it's not set for the given team. * @see Arena#lobbySpawns */ public Location getLobbySpawn(CrystalQuestTeam team) { return lobbySpawns.get(team); } /** * Checks if the lobbyspawns for all arenas are set. * * @return {@code true} when all team lobby spawns are set, {@code false} when at least one team * lobby is not setup correctly. */ public boolean areLobbySpawnsSet() { for (CrystalQuestTeam team : getTeams()) { Location lobbyspawn = getLobbySpawn(team); if (lobbyspawn == null) { return false; } } return true; } /** * Toggles the crystalquest.vip requirement on the arenas. * * @param isVip * True if VIP is needed. False if VIP is not needed. * @see Arena#vip */ public void setVip(boolean isVip) { this.vip = isVip; } /** * Checks if it is an arenas only for people with the crystalquest.vip node. * * @return True if it is VIP-only, False if it isn't * @see Arena#vip */ public boolean isVip() { return vip; } /** * Gets the arenas ID. * * @return The arenas ID * @see Arena#id */ public int getId() { return id; } /** * Gets the name of the arenas. * * @return Arena-name * @see Arena#name */ public String getName() { return name; } /** * Sets the name of the arenas. * * @param name * The new arenas-name. * @return true when the name is succesfully applied, false when the name already exists. * @see Arena#name */ public boolean setName(String name) { // Lol. I didn't bother to use regex. // You gotta admire young people's resourcefulness. try { Integer.parseInt(name); return false; } catch (Exception ignored) { } if (plugin.am.getArena(name) == null) { this.name = name; this.teamMenu = Bukkit.createInventory(null, 9, "Pick Team: " + this.getName()); plugin.menuPT.updateMenu(this); plugin.signHandler.updateSigns(); return true; } return false; } /** * Set the teams that can be joined in this arena. * * @param teams * Collection containing all the team possibilities for the arena. Can be at most 8 * teams and must contain at least 2 teams. * @throws IllegalArgumentException * When you entered more than 8 teams, or fewer than 2. */ public void setTeams(Collection<CrystalQuestTeam> teams) throws IllegalArgumentException { if (teams.size() > 8) { throw new IllegalArgumentException("You can only have 8 teams per arena!"); } if (teams.size() < 2) { throw new IllegalArgumentException("The arena must have at least 2 teams."); } this.teams.clear(); this.teams.addAll(teams); initializeScoreboard(); } /** * Set the teams that can be joined in this arena. * * @param team1 * The first team. * @param team2 * The second team. * @param other * All the other teams, must be at most 6. * @throws IllegalArgumentException * When you entered more than 8 teams. */ public void setTeams(CrystalQuestTeam team1, CrystalQuestTeam team2, CrystalQuestTeam... other) throws IllegalArgumentException { if (other.length > 6) { throw new IllegalArgumentException("Amount of teams must be at most 8!"); } this.teams.clear(); this.teams.add(team1); this.teams.add(team2); Collections.addAll(this.teams, other); initializeScoreboard(); } /** * Returns the amount of teams available for the arenas. * * @return The amount of teams of the arenas. * @see Arena#teams */ public int getTeamCount() { return teams.size(); } /** * Get the minimum amount of players for an arenas to start. * * @return The minimum amount of players to start. * @see Arena#minPlayers */ public int getMinPlayers() { return minPlayers; } /** * Set the minimum amount of players for an arenas to start. * * @param minPlayers * The minimum amount of players. * @see Arena#minPlayers */ public void setMinPlayers(int minPlayers) { this.minPlayers = minPlayers; plugin.signHandler.updateSigns(); } /** * Get the maximum amount of players for an arenas to start. * * @return The maximum amount of players to start. * @see Arena#maxPlayers */ public int getMaxPlayers() { return maxPlayers; } /** * Set the maximum amount of players for an arenas to start. * * @param maxPlayers * The maximum amount of players. * @see Arena#maxPlayers */ public void setMaxPlayers(int maxPlayers) { this.maxPlayers = maxPlayers; plugin.signHandler.updateSigns(); } /** * Start the game! */ public void startGame() { ArenaStartEvent e = new ArenaStartEvent(this); Bukkit.getPluginManager().callEvent(e); if (e.isCancelled()) { return; } for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); plugin.im.setClassInventory(player); player.sendMessage(Broadcast.TAG + Broadcast.get("arena.started")); player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 20F, 20F); player.sendMessage(Broadcast.TAG + Broadcast.get("arena.using-class") .replace("%class%", SMeth.setColours(plugin.getConfig().getString( "kit." + plugin.im.playerClass.get(player.getUniqueId()) + ".name")))); } setInGame(true); Random ran = new Random(); for (UUID id : getPlayers()) { Player player = Bukkit.getPlayer(id); boolean isTeamSpawns = false; for (int i = 0; i < getTeamCount(); i++) { if (getTeamSpawns().get(CrystalQuestTeam.valueOf(i)).size() > 0) { isTeamSpawns = true; } } if (isTeamSpawns) { CrystalQuestTeam team = getTeam(player); player.teleport(getTeamSpawns().get(team).get(ran.nextInt(getTeamSpawns().get(team).size()))); } else { player.teleport((getPlayerSpawns().get(ran.nextInt(getPlayerSpawns().size())))); } } plugin.signHandler.updateSigns(); Collection<CrystalQuestTeam> allPresentTeams = playerTeams.values(); for (CrystalQuestTeam team : getTeams()) { if (!allPresentTeams.contains(team)) { points.getScoreboard().resetScores(team.toString()); } } } /** * Get the score of the given team. * * @param team * The team to get the score of. * @return The score of the given team. * @throws IllegalStateException * When the given team is not present in the arena. */ public Score getScoreObject(CrystalQuestTeam team) throws IllegalStateException { if (!hasTeam(team)) { throw new IllegalStateException("CrystalQuestTeam " + team.getName() + " is not " + "present in the arena."); } return scoreboardScores.get(team); } /** * Get the team object (scoreboard) of a given team. * * @param team * The team to get the scoreboard score of. * @return The scoreboard Team corresponding to the given CrystalQuest Team. * @throws IllegalStateException * When the given team is not present in the arena. */ public Team getTeamObject(CrystalQuestTeam team) throws IllegalStateException { if (!hasTeam(team)) { throw new IllegalStateException("CrystalQuestTeam " + team.getName() + " is not " + "present in the arena."); } return scoreboardTeams.get(team); } /** * Adds points to a team * * @param team * The team to add the score to. * @param scoreToAdd * The points to add. */ public void addScore(CrystalQuestTeam team, int scoreToAdd) { Score score = getScoreObject(team); score.setScore(score.getScore() + scoreToAdd); } /** * Sets the score of a team. * * @param team * The team to get the score of. * @param newScore * The new score. */ public void setScore(CrystalQuestTeam team, int newScore) { Score score = getScoreObject(team); score.setScore(newScore); } /** * Gets the score of a team * * @param team * The team to get the score of. * @return The score of the given team. */ public int getScore(CrystalQuestTeam team) { if (getScoreboardTeams() == null) { return Integer.MIN_VALUE; } Score score = getScoreObject(team); return score.getScore(); } /** * @deprecated Uses the old team system. There is no alternative however. */ @Deprecated public List<Location> getLobbySpawns() { return getTeams().stream() .map(this::getLobbySpawn) .collect(Collectors.toList()); } }