diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java index 29abf4352..183b32313 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilAlg.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Random; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import net.minecraft.server.v1_8_R3.AxisAlignedBB; @@ -162,14 +163,9 @@ public class UtilAlg public static T Random(Set set) { - List list = new ArrayList(); - - list.addAll(set); - - return Random(list); + return Random(new ArrayList<>(set)); } - public static T Random(List list) { if (list.isEmpty()) @@ -193,6 +189,19 @@ public class UtilAlg return element; } + public static void shuffle(T[] array) + { + int size = array.length; + + for (int from = 0; from < size; from++) + { + int to = UtilMath.r(size); + T temp = array[from]; + array[from] = array[to]; + array[to] = temp; + } + } + public static List getBox(Block cornerA, Block cornerB) { if (cornerA == null || cornerB == null || (cornerA.getWorld() != cornerB.getWorld())) @@ -353,7 +362,7 @@ public class UtilAlg for (Entity loc : locs) { - double dist = UtilMath.offset(mid, loc); + double dist = UtilMath.offsetSquared(mid, loc); if (bestLoc == null || dist < bestDist) { @@ -372,7 +381,7 @@ public class UtilAlg for (Location loc : locs) { - double dist = UtilMath.offset(mid, loc); + double dist = UtilMath.offsetSquared(mid, loc); if (bestLoc == null || dist < bestDist) { @@ -391,7 +400,7 @@ public class UtilAlg for (Location loc : locs) { - double dist = UtilMath.offset(mid, loc); + double dist = UtilMath.offsetSquared(mid, loc); if (bestLoc == null || dist > bestDist) { @@ -414,58 +423,31 @@ public class UtilAlg isInPyramid(player.getLocation().getDirection(), UtilAlg.getTrajectory(player.getEyeLocation(), target.getLocation()), angleLimit); } - public static Location getLocationAwayFromPlayers(List locs, ArrayList players) + public static Location getLocationAwayFromPlayers(List locations, List players) { - Location bestLoc = null; - double bestDist = 0; - - for (Location loc : locs) - { - double closest = -1; - - for (Player player : players) - { - //Different Worlds - if (!player.getWorld().equals(loc.getWorld())) - continue; - - double dist = UtilMath.offsetSquared(player.getLocation(), loc); - - if (closest == -1 || dist < closest) - { - closest = dist; - } - } - - if (closest == -1) - continue; - - if (bestLoc == null || closest > bestDist) - { - bestLoc = loc; - bestDist = closest; - } - } - - return bestLoc; + return getLocationAwayFromOtherLocations(locations, players.stream() + .map(Entity::getLocation) + .collect(Collectors.toList())); } - public static Location getLocationAwayFromOtherLocations(ArrayList locs, ArrayList players) + public static Location getLocationAwayFromOtherLocations(List locations, List players) { - Location bestLoc = null; + Location bestLocation = null; double bestDist = 0; - for (Location loc : locs) + for (Location location : locations) { double closest = -1; for (Location player : players) { //Different Worlds - if (!player.getWorld().equals(loc.getWorld())) + if (!player.getWorld().equals(location.getWorld())) + { continue; + } - double dist = UtilMath.offsetSquared(player, loc); + double dist = UtilMath.offsetSquared(player, location); if (closest == -1 || dist < closest) { @@ -473,17 +455,19 @@ public class UtilAlg } } - if (closest == -1) - continue; +// if (closest == -1) +// { +// continue; +// } - if (bestLoc == null || closest > bestDist) + if (bestLocation == null || closest > bestDist) { - bestLoc = loc; + bestLocation = location; bestDist = closest; } } - return bestLoc; + return bestLocation; } public static Location getLocationNearPlayers(List locs, ArrayList players, ArrayList dontOverlap) diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilColor.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilColor.java index 323b80dba..b7a4b8b9f 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilColor.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilColor.java @@ -87,7 +87,7 @@ public class UtilColor case 2: return ChatColor.DARK_PURPLE; case 3: - return ChatColor.BLUE; + return ChatColor.AQUA; case 4: return ChatColor.YELLOW; case 5: diff --git a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java index c58c83881..89dd86151 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/chat/Chat.java @@ -866,7 +866,7 @@ public class Chat extends MiniPlugin { BaseComponent text = component.getText(sender); - if (text.toPlainText().isEmpty()) + if (text == null || text.toPlainText().isEmpty()) { continue; } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java index 62a00686a..980df8554 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java @@ -113,6 +113,8 @@ public enum GameDisplay CakeWars4("Cake Wars Standard", "Cake Wars", Material.CAKE, (byte)0, GameCategory.INTERMEDIATE, 73, true), CakeWarsDuos("Cake Wars Duos", "Cake Wars", Material.SUGAR, (byte)0, GameCategory.INTERMEDIATE, 74, false), + NanoGames("Nano Games", Material.JUKEBOX, (byte)0, GameCategory.CASUAL, 75, false), + GemHunters("Gem Hunters", Material.EMERALD, (byte) 0, GameCategory.EVENT, 71, false), Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999, false), diff --git a/Plugins/Mineplex.Core/src/mineplex/core/game/status/GameInfo.java b/Plugins/Mineplex.Core/src/mineplex/core/game/status/GameInfo.java index 156cc9893..f29d5bb9b 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/game/status/GameInfo.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/game/status/GameInfo.java @@ -86,6 +86,7 @@ public class GameInfo public enum GameDisplayStatus { // Sorted by priority + ALWAYS_OPEN, STARTING, VOTING, WAITING, diff --git a/Plugins/Mineplex.Core/src/mineplex/core/noteblock/NotePlayer.java b/Plugins/Mineplex.Core/src/mineplex/core/noteblock/NotePlayer.java index dabd91908..4baf84877 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/noteblock/NotePlayer.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/noteblock/NotePlayer.java @@ -21,8 +21,8 @@ public class NotePlayer private volatile float _volumeMult; private volatile boolean _loop; private volatile int _tick; - private volatile boolean _finished; - private volatile Player[] _players = null; + private volatile boolean _finished, _paused; + private volatile Player[] _players = null; public NotePlayer(JavaPlugin plugin, NoteSong song, Predicate shouldPlay, float volumeMult, boolean loop, Player... players) { @@ -53,6 +53,12 @@ public class NotePlayer { while (!_finished) { + if (_paused) + { + sleep(); + continue; + } + _tick++; if (_tick > _song.getLength()) { @@ -75,15 +81,7 @@ public class NotePlayer } playTick(_tick); - - try - { - Thread.sleep(_sleepMs); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } + sleep(); } }); @@ -97,7 +95,7 @@ public class NotePlayer for (Player player : playerArray) { - if (_shouldPlay != null && _shouldPlay.test(player)) + if (_shouldPlay == null || _shouldPlay.test(player)) { players.add(player); } @@ -123,8 +121,25 @@ public class NotePlayer } } + private void sleep() + { + try + { + Thread.sleep(_sleepMs); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + public void cancel() { _finished = true; } + + public void setPaused(boolean paused) + { + _paused = paused; + } } diff --git a/Plugins/Mineplex.Game.Nano/plugin.yml b/Plugins/Mineplex.Game.Nano/plugin.yml new file mode 100644 index 000000000..dd12b1ff2 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/plugin.yml @@ -0,0 +1,4 @@ +name: NanoGames +main: mineplex.game.nano.NanoGames +version: 0.1 +loadbefore: [MineplexAnticheat] diff --git a/Plugins/Mineplex.Game.Nano/pom.xml b/Plugins/Mineplex.Game.Nano/pom.xml new file mode 100644 index 000000000..1b369e29c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + + com.mineplex + mineplex-plugin + dev-SNAPSHOT + ../plugin.xml + + + NanoGames + mineplex-game-nano + + + + ${project.groupId} + mineplex-minecraft-game-core + ${project.version} + + + \ No newline at end of file diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/GameManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/GameManager.java new file mode 100644 index 000000000..5a90b4046 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/GameManager.java @@ -0,0 +1,17 @@ +package mineplex.game.nano; + +import mineplex.core.MiniPlugin; + +public class GameManager extends MiniPlugin +{ + + protected final NanoManager _manager; + + protected GameManager(String name) + { + super(name); + + _manager = require(NanoManager.class); + } + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoGames.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoGames.java new file mode 100644 index 000000000..c8754b068 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoGames.java @@ -0,0 +1,185 @@ +package mineplex.game.nano; + +import org.bukkit.Bukkit; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.CustomTagFix; +import mineplex.core.FoodDupeFix; +import mineplex.core.PacketsInteractionFix; +import mineplex.core.TwitchIntegrationFix; +import mineplex.core.account.CoreClientManager; +import mineplex.core.achievement.AchievementManager; +import mineplex.core.admin.command.AdminCommands; +import mineplex.core.antihack.RelationProvider; +import mineplex.core.blockrestore.BlockRestore; +import mineplex.core.blood.Blood; +import mineplex.core.boosters.BoosterManager; +import mineplex.core.chat.Chat; +import mineplex.core.chatsnap.SnapshotManager; +import mineplex.core.chatsnap.SnapshotPlugin; +import mineplex.core.chatsnap.SnapshotRepository; +import mineplex.core.command.CommandCenter; +import mineplex.core.common.Constants; +import mineplex.core.communities.CommunityManager; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.creature.Creature; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.playerdisguise.PlayerDisguiseManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.elo.EloManager; +import mineplex.core.friend.FriendManager; +import mineplex.core.gadget.GadgetManager; +import mineplex.core.give.Give; +import mineplex.core.ignore.IgnoreManager; +import mineplex.core.incognito.IncognitoManager; +import mineplex.core.inventory.InventoryManager; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.memory.MemoryFix; +import mineplex.core.menu.MenuManager; +import mineplex.core.message.MessageManager; +import mineplex.core.monitor.LagMeter; +import mineplex.core.packethandler.PacketHandler; +import mineplex.core.party.PartyManager; +import mineplex.core.pet.PetManager; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Portal; +import mineplex.core.preferences.PreferencesManager; +import mineplex.core.profileCache.ProfileCacheManager; +import mineplex.core.punish.Punish; +import mineplex.core.recharge.Recharge; +import mineplex.core.report.ReportManager; +import mineplex.core.report.ReportPlugin; +import mineplex.core.serverConfig.ServerConfiguration; +import mineplex.core.sound.SoundNotifier; +import mineplex.core.stats.StatsManager; +import mineplex.core.status.ServerStatusManager; +import mineplex.core.teamspeak.TeamspeakManager; +import mineplex.core.teleport.Teleport; +import mineplex.core.thank.ThankManager; +import mineplex.core.titles.Titles; +import mineplex.core.treasure.TreasureManager; +import mineplex.core.twofactor.TwoFactorAuth; +import mineplex.core.updater.FileUpdater; +import mineplex.core.updater.Updater; +import mineplex.core.velocity.VelocityFix; +import mineplex.core.visibility.VisibilityManager; +import mineplex.core.website.WebsiteLinkManager; +import mineplex.game.nano.game.Game; +import mineplex.minecraft.game.core.combat.CombatManager; +import mineplex.minecraft.game.core.condition.ConditionManager; +import mineplex.minecraft.game.core.damage.DamageManager; + +import static mineplex.core.Managers.require; + +public class NanoGames extends JavaPlugin +{ + + private NanoManager _gameManager; + + @Override + public void onEnable() + { + getServer().getServicesManager().register(RelationProvider.class, (player, target) -> + { + if (target instanceof Player) + { + return _gameManager.canHurt(player, (Player) target); + } + else + { + Game game = _gameManager.getGame(); + return target instanceof LivingEntity && game != null && game.isLive(); + } + }, this, ServicePriority.Normal); + + Bukkit.setSpawnRadius(0); + getConfig().addDefault(Constants.WEB_CONFIG_KEY, Constants.WEB_ADDRESS); + getConfig().set(Constants.WEB_CONFIG_KEY, getConfig().getString(Constants.WEB_CONFIG_KEY)); + saveConfig(); + + require(ProfileCacheManager.class); + CommandCenter.Initialize(this); + CoreClientManager clientManager = new CoreClientManager(this); + CommandCenter.Instance.setClientManager(clientManager); + + ItemStackFactory.Initialize(this, false); + Recharge.Initialize(this); + require(VisibilityManager.class); + Give.Initialize(this); + Punish punish = new Punish(this, clientManager); + BlockRestore blockRestore = require(BlockRestore.class); + DonationManager donationManager = require(DonationManager.class); + + ServerConfiguration serverConfiguration = new ServerConfiguration(this, clientManager); + ServerStatusManager serverStatusManager = new ServerStatusManager(this, clientManager, new LagMeter(this, clientManager)); + + PacketHandler packetHandler = require(PacketHandler.class); + DisguiseManager disguiseManager = require(DisguiseManager.class); + require(PlayerDisguiseManager.class); + IncognitoManager incognito = new IncognitoManager(this, clientManager, packetHandler); + PreferencesManager preferenceManager = new PreferencesManager(this, incognito, clientManager); + + incognito.setPreferencesManager(preferenceManager); + + Creature creature = new Creature(this); + creature.SetDisableCustomDrops(true); + InventoryManager inventoryManager = new InventoryManager(this, clientManager); + PetManager petManager = new PetManager(this, clientManager, donationManager, inventoryManager, disguiseManager, creature, blockRestore); + + Portal portal = new Portal(); + + new Teleport(this, clientManager); + + IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); + + FriendManager friendManager = require(FriendManager.class); + + StatsManager statsManager = new StatsManager(this, clientManager); + EloManager eloManager = new EloManager(this, clientManager); + AchievementManager achievementManager = new AchievementManager(statsManager, clientManager, donationManager, incognito, eloManager); + + PartyManager partyManager = new PartyManager(); + + String boosterGroup = serverConfiguration.getServerGroup().getBoosterGroup(); + ThankManager thankManager = new ThankManager(this, clientManager, donationManager); + BoosterManager boosterManager = new BoosterManager(this, boosterGroup, clientManager, donationManager, inventoryManager, thankManager); + + new CosmeticManager(this, clientManager, donationManager, inventoryManager, require(GadgetManager.class), petManager, require(TreasureManager.class), boosterManager, punish).setActive(false); + + new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, require(Chat.class)); + new MemoryFix(this); + new MenuManager(this); + new FileUpdater(this, portal, serverStatusManager.getCurrentServerName(), serverStatusManager.getRegion(), GenericServer.HUB); + new CustomTagFix(this, packetHandler); + new PacketsInteractionFix(this, packetHandler); + + SnapshotManager snapshotManager = new SnapshotManager(this, new SnapshotRepository(serverStatusManager.getCurrentServerName(), getLogger())); + ReportManager reportManager = new ReportManager(this, snapshotManager, clientManager, incognito, punish, serverStatusManager.getRegion(), serverStatusManager.getCurrentServerName(), 3); + new SnapshotPlugin(this, snapshotManager, clientManager); + new ReportPlugin(this, reportManager); + new VelocityFix(this); + new FoodDupeFix(this); + + CombatManager combatManager = require(CombatManager.class); + ConditionManager conditionManager = new ConditionManager(this); + DamageManager damage = new DamageManager(this, combatManager, null, disguiseManager, conditionManager); + conditionManager.setDamageManager(damage); + new Blood(this); + + require(CommunityManager.class); + require(Updater.class); + require(Titles.class).forceDisable(); + require(TwoFactorAuth.class); + require(TeamspeakManager.class); + new WebsiteLinkManager(this, clientManager); + require(TwitchIntegrationFix.class); + require(SoundNotifier.class); + + new AdminCommands(); + + _gameManager = require(NanoManager.class); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoManager.java new file mode 100644 index 000000000..10e9299cd --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoManager.java @@ -0,0 +1,454 @@ +package mineplex.game.nano; + +import java.util.HashSet; +import java.util.Set; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.TextComponent; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.achievement.AchievementManager; +import mineplex.core.antihack.AntiHack; +import mineplex.core.boosters.BoosterManager; +import mineplex.core.chat.Chat; +import mineplex.core.chat.format.LevelFormatComponent; +import mineplex.core.chat.format.RankFormatComponent; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.cosmetic.CosmeticManager; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.game.GameDisplay; +import mineplex.core.incognito.IncognitoManager; +import mineplex.core.incognito.events.IncognitoStatusChangeEvent; +import mineplex.core.serverConfig.ServerConfiguration; +import mineplex.core.stats.StatsManager; +import mineplex.core.status.ServerStatusManager; +import mineplex.game.nano.commands.game.GameCommand; +import mineplex.game.nano.commands.spectator.SpectatorCommand; +import mineplex.game.nano.cycle.GameCycle; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.components.currency.GameCurrencyManager; +import mineplex.game.nano.game.components.damage.GameDamageManager; +import mineplex.game.nano.game.components.player.GamePlayerManager; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.components.world.GameWorldManager; +import mineplex.game.nano.lobby.AFKManager; +import mineplex.game.nano.lobby.LobbyManager; +import mineplex.game.nano.lobby.ReturnToHubManager; +import mineplex.game.nano.status.GameStatusManager; +import mineplex.game.nano.world.GameWorld; +import mineplex.minecraft.game.core.IRelation; +import mineplex.minecraft.game.core.condition.ConditionManager; +import mineplex.minecraft.game.core.damage.DamageManager; +import mineplex.serverdata.data.ServerGroup; + +@ReflectivelyCreateMiniPlugin +public class NanoManager extends MiniPlugin implements IRelation +{ + + public enum Perm implements Permission + { + GAME_COMMAND, + SPECTATOR_COMMAND, + AUTO_OP + } + + private static final String HEADER_FOOTER = C.cDGreen + C.Strike + "============================================="; + + public static String getHeaderFooter() + { + return HEADER_FOOTER; + } + + private static final GameDisplay GAME_DISPLAY = GameDisplay.NanoGames; + + public static GameDisplay getGameDisplay() + { + return GAME_DISPLAY; + } + + // Standard + private final CoreClientManager _clientManager; + private final DonationManager _donationManager; + + // Achievement + private final StatsManager _statsManager; + private final AchievementManager _achievementManager; + + // Chat + private final Chat _chat; + + // Vanish + private final IncognitoManager _incognitoManager; + private final Set _spectators; + + // Conditions + private final ConditionManager _conditionManager; + + // Disguise + private final DisguiseManager _disguiseManager; + + // Cosmetics + private final CosmeticManager _cosmeticManager; + + // Booster + private final BoosterManager _boosterManager; + + // AntiCheat + private final AntiHack _antiHack; + + // Damage + private final DamageManager _damageManager; + private final GameDamageManager _gameDamageManager; + + // World + private final GameWorldManager _gameWorldManager; + + // Player + private final GamePlayerManager _gamePlayerManager; + + // Lobby + private final LobbyManager _lobbyManager; + + // Currency + private final GameCurrencyManager _currencyManager; + + // Server + private final ServerGroup _serverGroup; + + // Game + private Game _game; + private final GameCycle _gameCycle; + + private NanoManager() + { + super("Game"); + + GameWorld.deleteOldFolders(this); + + _clientManager = require(CoreClientManager.class); + _donationManager = require(DonationManager.class); + + _statsManager = require(StatsManager.class); + _achievementManager = require(AchievementManager.class); + + _chat = require(Chat.class); + _chat.setFormatComponents( + player -> + { + if (_game == null || _game.isAlive(player)) + { + return null; + } + + TextComponent message = new TextComponent("Dead"); + message.setColor(ChatColor.GRAY); + return message; + }, + new LevelFormatComponent(_achievementManager), + new RankFormatComponent(_clientManager), + player -> + { + TextComponent message = new TextComponent(player.getName()); + message.setColor(ChatColor.YELLOW); + return message; + } + ); + + _incognitoManager = require(IncognitoManager.class); + _spectators = new HashSet<>(); + + _conditionManager = require(ConditionManager.class); + + _disguiseManager = require(DisguiseManager.class); + + _cosmeticManager = require(CosmeticManager.class); + + _boosterManager = require(BoosterManager.class); + + _antiHack = require(AntiHack.class); + + _damageManager = require(DamageManager.class); + _gameDamageManager = require(GameDamageManager.class); + + _gameWorldManager = require(GameWorldManager.class); + _gamePlayerManager = require(GamePlayerManager.class); + + _lobbyManager = require(LobbyManager.class); + require(ReturnToHubManager.class); + + _currencyManager = require(GameCurrencyManager.class); + + _serverGroup = require(ServerConfiguration.class).getServerGroup(); + + require(GameStatusManager.class); + require(AFKManager.class); + + _gameCycle = require(GameCycle.class); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.ADMIN.setPermission(Perm.GAME_COMMAND, true, true); + PermissionGroup.PLAYER.setPermission(Perm.SPECTATOR_COMMAND, true, true); + PermissionGroup.LT.setPermission(Perm.AUTO_OP, true, true); + } + + @Override + public void addCommands() + { + addCommand(new GameCommand(this)); + addCommand(new SpectatorCommand(this)); + } + + public boolean canStartGame() + { + int players = UtilServer.getPlayersCollection().size() - _spectators.size(); + return players >= _serverGroup.getMinPlayers() && _serverGroup.getGameAutoStart(); + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + + player.setOp(_clientManager.Get(player).hasPermission(Perm.AUTO_OP)); + + if (isSpectator(player)) + { + event.setJoinMessage(null); + } + else + { + event.setJoinMessage(F.sys("Join", player.getName())); + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + + event.setQuitMessage(F.sys("Quit", player.getName())); + _spectators.remove(player); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void playerVanish(IncognitoStatusChangeEvent event) + { + Player player = event.getPlayer(); + + if (event.getNewState()) + { + Bukkit.broadcastMessage(F.sys("Quit", player.getName())); + + if (_game != null && _game.isAlive(player)) + { + _game.addSpectator(player, true, true); + } + } + else + { + Bukkit.broadcastMessage(F.sys("Join", player.getName())); + } + } + + public void setSpectator(Player player, boolean spectator) + { + if (spectator) + { + _spectators.add(player); + } + else + { + _spectators.remove(player); + } + } + + public boolean isSpectator(Player player) + { + if (_incognitoManager.Get(player).Status) + { + _spectators.add(player); + return true; + } + + return _spectators.contains(player); + } + + public Set getSpectators() + { + return _spectators; + } + + @Override + public boolean canHurt(Player a, Player b) + { + // Either safe + if (isSafe(a) || isSafe(b)) + { + return false; + } + + // No Hook + if (_gameDamageManager.getHook() == null) + { + return false; + } + + // Self Damage + if (a.equals(b)) + { + return _gameDamageManager.getHook().isSelfEnabled(); + } + + // PVP + if (!_gameDamageManager.getHook().isPvpEnabled()) + { + return false; + } + + GameTeam tA = _game.getTeam(a), tB = _game.getTeam(b); + + // No need for null check since isSafe has done that already + if (tA.equals(tB)) + { + return _gameDamageManager.getHook().isTeamSelfEnabled(); + } + + return true; + } + + @Override + public boolean canHurt(String a, String b) + { + return canHurt(UtilPlayer.searchExact(a), UtilPlayer.searchExact(b)); + } + + @Override + public boolean isSafe(Player a) + { + return _game == null || !_game.isLive() || !_game.isAlive(a) || _game.hasRespawned(a); + } + + public CoreClientManager getClientManager() + { + return _clientManager; + } + + public DonationManager getDonationManager() + { + return _donationManager; + } + + public StatsManager getStatsManager() + { + return _statsManager; + } + + public AchievementManager getAchievementManager() + { + return _achievementManager; + } + + public Chat getChat() + { + return _chat; + } + + public IncognitoManager getIncognitoManager() + { + return _incognitoManager; + } + + public ConditionManager getConditionManager() + { + return _conditionManager; + } + + public DisguiseManager getDisguiseManager() + { + return _disguiseManager; + } + + public CosmeticManager getCosmeticManager() + { + return _cosmeticManager; + } + + public BoosterManager getBoosterManager() + { + return _boosterManager; + } + + public AntiHack getAntiHack() + { + return _antiHack; + } + + public DamageManager getDamageManager() + { + return _damageManager; + } + + public GameDamageManager getGameDamageManager() + { + return _gameDamageManager; + } + + public GameWorldManager getGameWorldManager() + { + return _gameWorldManager; + } + + public GamePlayerManager getGamePlayerManager() + { + return _gamePlayerManager; + } + + public LobbyManager getLobbyManager() + { + return _lobbyManager; + } + + public GameCurrencyManager getCurrencyManager() + { + return _currencyManager; + } + + public ServerGroup getServerGroup() + { + return _serverGroup; + } + + public void setGame(Game game) + { + _game = game; + } + + public Game getGame() + { + return _game; + } + + public GameCycle getGameCycle() + { + return _gameCycle; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoPlayer.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoPlayer.java new file mode 100644 index 000000000..e5c6c009b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/NanoPlayer.java @@ -0,0 +1,88 @@ +package mineplex.game.nano; + +import net.minecraft.server.v1_8_R3.EntityPlayer; + +import org.bukkit.GameMode; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.disguise.disguises.DisguiseBase; + +public class NanoPlayer +{ + + public static void clear(NanoManager manager, Player player) + { + // Game Mode + player.setGameMode(GameMode.ADVENTURE); + + // Inventory + UtilPlayer.clearInventory(player); + UtilPlayer.closeInventoryIfOpen(player); + + // Potion Effects + manager.getConditionManager().EndCondition(player, null, null); + UtilPlayer.clearPotionEffects(player); + + // Falling + player.setFallDistance(0); + + // Vehicles + player.eject(); + player.leaveVehicle(); + + // Level + player.setLevel(0); + player.setExp(0); + + // Heath + player.setMaxHealth(20); + player.setHealth(player.getMaxHealth()); + + // Food + player.setFoodLevel(20); + player.setExhaustion(0); + + // Movement + player.setSprinting(false); + player.setSneaking(false); + + // Client Side + player.resetPlayerTime(); + player.resetPlayerWeather(); + + // Remove Arrows + ((CraftPlayer) player).getHandle().o(0); + + // Flight + player.setFlySpeed(0.1F); + player.setFlying(false); + player.setAllowFlight(false); + + // Things that could be affected by the current tick + manager.runSyncLater(() -> + { + player.setFireTicks(0); + UtilAction.zeroVelocity(player); + }, 0); + + // Disguise + DisguiseBase disguise = manager.getDisguiseManager().getActiveDisguise(player); + + if (disguise != null) + { + manager.getDisguiseManager().undisguise(disguise); + } + } + + public static void setSpectating(Player player, boolean spectating) + { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + entityPlayer.spectating = spectating; + entityPlayer.setGhost(spectating); + entityPlayer.k = !spectating; + } + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCommand.java new file mode 100644 index 000000000..851e3050b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCommand.java @@ -0,0 +1,32 @@ +package mineplex.game.nano.commands.game; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.MultiCommandBase; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; + +public class GameCommand extends MultiCommandBase +{ + + public GameCommand(NanoManager plugin) + { + super(plugin, Perm.GAME_COMMAND, "game"); + + AddCommand(new GameSetCommand(plugin)); + AddCommand(new GameStartCommand(plugin)); + AddCommand(new GameStopCommand(plugin)); + AddCommand(new GameCycleCommand(plugin)); + } + + @Override + protected void Help(Player caller, String[] args) + { + caller.sendMessage(F.help("/" + _aliasUsed + " set [map]", "Sets the next game and map", ChatColor.DARK_RED)); + caller.sendMessage(F.help("/" + _aliasUsed + " start", "Forcefully starts the game", ChatColor.DARK_RED)); + caller.sendMessage(F.help("/" + _aliasUsed + " stop", "Stops the current game", ChatColor.DARK_RED)); + caller.sendMessage(F.help("/" + _aliasUsed + " cycle", "Toggles the game cycle", ChatColor.DARK_RED)); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCycleCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCycleCommand.java new file mode 100644 index 000000000..327ce8d61 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameCycleCommand.java @@ -0,0 +1,27 @@ +package mineplex.game.nano.commands.game; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.C; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; + +public class GameCycleCommand extends CommandBase +{ + + GameCycleCommand(NanoManager plugin) + { + super(plugin, Perm.GAME_COMMAND, "cycle"); + } + + @Override + public void Execute(Player caller, String[] args) + { + boolean newState = !Plugin.getGameCycle().isTestingMode(); + + Bukkit.broadcastMessage(C.cAquaB + caller.getName() + " set testing mode to " + newState + "."); + Plugin.getGameCycle().setTestingMode(newState); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameSetCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameSetCommand.java new file mode 100644 index 000000000..c4f5ca70d --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameSetCommand.java @@ -0,0 +1,80 @@ +package mineplex.game.nano.commands.game; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; +import mineplex.game.nano.game.GameType; + +public class GameSetCommand extends CommandBase +{ + + GameSetCommand(NanoManager plugin) + { + super(plugin, Perm.GAME_COMMAND, "set"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + caller.sendMessage(F.main(Plugin.getName(), "Enter a valid game.")); + return; + } + + String game = args[0].toUpperCase(); + String map = null; + + if (args.length > 1) + { + map = Arrays.stream(args) + .skip(1) + .collect(Collectors.joining(" ")); + } + + GameType gameType; + + try + { + gameType = GameType.valueOf(game); + } + catch (IllegalArgumentException e) + { + caller.sendMessage(F.main(Plugin.getName(), F.name(game) + " is not a valid game.")); + return; + } + + Bukkit.broadcastMessage(C.cAquaB + caller.getName() + " set the next game to " + gameType.getName() + (map != null ? " and map to " + map : "")); + Plugin.getGameCycle().setNextGameMap(gameType, map); + } + + @Override + public List onTabComplete(CommandSender sender, String commandLabel, String[] args) + { + if (args.length == 0) + { + return Arrays.stream(GameType.values()) + .map(Enum::name) + .collect(Collectors.toList()); + } + else if (args.length == 1) + { + return Arrays.stream(GameType.values()) + .map(Enum::name) + .filter(s -> s.startsWith(args[0].toUpperCase())) + .collect(Collectors.toList()); + } + + return null; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStartCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStartCommand.java new file mode 100644 index 000000000..6ced89969 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStartCommand.java @@ -0,0 +1,36 @@ +package mineplex.game.nano.commands.game; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; +import mineplex.game.nano.game.Game; + +public class GameStartCommand extends CommandBase +{ + + GameStartCommand(NanoManager plugin) + { + super(plugin, Perm.GAME_COMMAND, "start"); + } + + @Override + public void Execute(Player caller, String[] args) + { + Game game = Plugin.getGame(); + + if (game == null) + { + Bukkit.broadcastMessage(C.cAquaB + caller.getName() + " started the game"); + Plugin.getGameCycle().checkForDeadGame(true); + } + else + { + caller.sendMessage(F.main(Plugin.getName(), "There is already a running game!")); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStopCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStopCommand.java new file mode 100644 index 000000000..d6d9a9335 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/game/GameStopCommand.java @@ -0,0 +1,37 @@ +package mineplex.game.nano.commands.game; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; + +public class GameStopCommand extends CommandBase +{ + + GameStopCommand(NanoManager plugin) + { + super(plugin, Perm.GAME_COMMAND, "stop"); + } + + @Override + public void Execute(Player caller, String[] args) + { + Game game = Plugin.getGame(); + + if (game == null) + { + caller.sendMessage(F.main(Plugin.getName(), "No game running.")); + } + else if (game.getState() != GameState.End) + { + Bukkit.broadcastMessage(C.cAquaB + caller.getName() + " stopped the game"); + game.setState(GameState.End); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/spectator/SpectatorCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/spectator/SpectatorCommand.java new file mode 100644 index 000000000..f9ee5c0fc --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/commands/spectator/SpectatorCommand.java @@ -0,0 +1,40 @@ +package mineplex.game.nano.commands.spectator; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoManager.Perm; + +public class SpectatorCommand extends CommandBase +{ + + public SpectatorCommand(NanoManager plugin) + { + super(plugin, Perm.SPECTATOR_COMMAND, "spec", "spectate"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (Plugin.getIncognitoManager().Get(caller).Status) + { + caller.sendMessage(F.main(Plugin.getName(), "You cannot toggle spectator mode while vanished.")); + return; + } + + boolean spectator = !Plugin.isSpectator(caller); + + Plugin.setSpectator(caller, spectator); + + if (spectator) + { + caller.sendMessage(F.main(Plugin.getName(), "You will be a spectator in the next game.")); + } + else + { + caller.sendMessage(F.main(Plugin.getName(), "You will participate in the next game.")); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/cycle/GameCycle.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/cycle/GameCycle.java new file mode 100644 index 000000000..26c894459 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/cycle/GameCycle.java @@ -0,0 +1,284 @@ +package mineplex.game.nano.cycle; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class GameCycle extends GameManager +{ + + private List _gamePool; + + // Preferences + private GameType _gamePreference; + private String _mapPreference; + + // Testing mode + private GameType _lastGame; + private boolean _testingMode; + + private GameCycle() + { + super("Game Cycle"); + + _gamePool = new ArrayList<>(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void playerJoin(PlayerJoinEvent event) + { + if (_manager.canStartGame()) + { + runSyncLater(() -> checkForDeadGame(false), 10); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void gameDeath(GameStateChangeEvent event) + { + if (event.getState() != GameState.Dead) + { + return; + } + + checkForDeadGame(false); + } + + public void checkForDeadGame(boolean force) + { + Game game = _manager.getGame(); + + // No Game. Make a new one + if (game == null) + { + if (force || _manager.canStartGame()) + { + createGame(); + } + } + // Dead Game. Kill it + else if (game.getState() == GameState.Dead) + { + game.getLifetime().end(); + _manager.setGame(null); + + // Make the next game. + if (force || _manager.canStartGame()) + { + createGame(); + } + // Cannot start so move all players to lobby + else + { + _manager.getLobbyManager().ensureInLobby(); + } + + _manager.runSyncTimer(new BukkitRunnable() + { + int attempts = 0; + + @Override + public void run() + { + if (killDeadGame(game, ++attempts)) + { + log("Successfully killed " + game.getClass().getSimpleName()); + cancel(); + } + } + }, 10, 10); + } + } + + private boolean killDeadGame(Game game, int attempts) + { + List players = game.getMineplexWorld().getWorld().getPlayers(); + boolean tooLong = attempts > 5; + + if (tooLong) + { + log("Took too long, " + players.toString() + " are still in world. Next game failed to load?"); + + players.forEach(player -> + { + player.remove(); + player.kickPlayer("Dead World"); + }); + } + + if (players.isEmpty() || tooLong) + { + log(game.getClass().getSimpleName() + " world is empty, killing..."); + game.getGameWorld().unloadWorld(); + return true; + } + + log("Unable to kill " + game.getClass().getSimpleName() + ", players are still in world. Attempt: " + attempts); + return false; + } + + private void createGame() + { + String error = createGameError(); + + if (error == null) + { + log("Successfully created " + _manager.getGame().getGameType().getName()); + } + else + { + log("Failed to create game! Error: {" + error + "}, Game Preference : {" + _gamePreference + "}, Map Preference : {" + _mapPreference + "}!"); + } + } + + private String createGameError() + { + GameType gameType = getNextGameType(); + + if (gameType == null) + { + return "getNextGameType was null"; + } + + File map = getNextMap(gameType); + + if (map == null) + { + return "getNextMap was null"; + } + + _gamePool.remove(gameType); + _gamePreference = null; + _mapPreference = null; + _lastGame = gameType; + + try + { + Game game = gameType.getGameClass().getConstructor(NanoManager.class).newInstance(_manager); + + _manager.setGame(game); + game.setupGameWorld(map); + } + catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) + { + e.printStackTrace(); + return e.getMessage(); + } + + return null; + } + + private GameType getNextGameType() + { + if (_gamePreference != null) + { + log("Setting by Game Preference : " + _gamePreference); + return _gamePreference; + } + + // Testing mode + if (_testingMode && _lastGame != null) + { + log("Setting by last game"); + return _lastGame; + } + + if (_gamePool == null || _gamePool.isEmpty()) + { + List gameTypes = new ArrayList<>(Arrays.asList(GameType.values())); + + if (_lastGame != null) + { + gameTypes.remove(_lastGame); + } + + log("No games in pool. Adding " + gameTypes); + _gamePool = gameTypes; + } + + GameType gameType = UtilAlg.Random(_gamePool); + + log("Setting by Random : " + gameType); + return gameType; + } + + private File getNextMap(GameType gameType) + { + File directory = new File(gameType.getMapDirectory()); + + if (!directory.exists() && !directory.mkdirs()) + { + log("Failed to create non-existent dirs"); + return null; + } + + File[] mapZips = directory.listFiles((dir, name) -> name.endsWith(".zip")); + + if (mapZips == null) + { + return null; + } + + log("Found maps: " + Arrays.stream(mapZips) + .map(File::getName) + .collect(Collectors.joining(","))); + + File file; + + if (_mapPreference == null) + { + log("Setting by Map Random"); + file = UtilMath.randomElement(mapZips); + } + else + { + log("Setting by Map Preference : " + _mapPreference); + file = new File(directory + File.separator + _mapPreference + ".zip"); + + if (!file.exists()) + { + log("Map Preference : " + _mapPreference + " did not exist!"); + _mapPreference = null; + return getNextMap(gameType); + } + } + + return file != null && file.exists() ? file : null; + } + + public void setNextGameMap(GameType gameType, String map) + { + _gamePreference = gameType; + _mapPreference = map; + } + + public void setTestingMode(boolean testingMode) + { + _testingMode = testingMode; + } + + public boolean isTestingMode() + { + return _testingMode; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/Game.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/Game.java new file mode 100644 index 000000000..582566a82 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/Game.java @@ -0,0 +1,327 @@ +package mineplex.game.nano.game; + +import java.io.File; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +import mineplex.core.Managers; +import mineplex.core.antihack.AntiHack; +import mineplex.core.common.util.UtilServer; +import mineplex.core.lifetimes.Lifetimed; +import mineplex.core.lifetimes.ListenerComponent; +import mineplex.core.lifetimes.PhasedLifetime; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.components.compass.GameCompassComponent; +import mineplex.game.nano.game.components.currency.CurrencyComponent; +import mineplex.game.nano.game.components.damage.GameDamageComponent; +import mineplex.game.nano.game.components.end.GameEndComponent; +import mineplex.game.nano.game.components.player.GamePlayerComponent; +import mineplex.game.nano.game.components.prepare.GamePrepareComponent; +import mineplex.game.nano.game.components.scoreboard.GameScoreboardComponent; +import mineplex.game.nano.game.components.spectator.GameSpectatorComponent; +import mineplex.game.nano.game.components.spectator.SpectatorComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.components.team.GameTeamComponent; +import mineplex.game.nano.game.components.team.TeamComponent; +import mineplex.game.nano.game.components.world.GameWorldComponent; +import mineplex.game.nano.game.components.world.GameWaterComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.world.GameWorld; + +public abstract class Game extends ListenerComponent implements Lifetimed, TeamComponent, SpectatorComponent, CurrencyComponent +{ + + public enum GameState + { + Loading, Prepare, Live, End, Dead + } + + private final PhasedLifetime _lifetime; + + protected final NanoManager _manager; + private final GameType _gameType; + private final String[] _description; + + // World Data + protected GameWorld _gameWorld; + protected MineplexWorld _mineplexWorld; + + // Game State + private long _stateTime; + + // Standard Components + protected final GamePrepareComponent _prepareComponent; + protected final GameTeamComponent _teamComponent; + protected final GameSpectatorComponent _spectatorComponent; + protected final GameScoreboardComponent _scoreboardComponent; + protected final GameDamageComponent _damageComponent; + protected final GameWorldComponent _worldComponent; + protected final GamePlayerComponent _playerComponent; + protected final GameWaterComponent _waterComponent; + protected final GameCompassComponent _compassComponent; + protected final GameEndComponent _endComponent; + + // Winners + private GamePlacements _placements; + private GameTeam _winningTeam; + + public Game(NanoManager manager, GameType gameType, String[] description) + { + _lifetime = new PhasedLifetime<>(); + _lifetime.register(this); + _lifetime.start(GameState.Loading); + + _manager = manager; + _gameType = gameType; + _description = description; + + _prepareComponent = new GamePrepareComponent(this); + _teamComponent = new GameTeamComponent(this); + _spectatorComponent = new GameSpectatorComponent(this); + _scoreboardComponent = new GameScoreboardComponent(this); + _damageComponent = new GameDamageComponent(this); + _worldComponent = new GameWorldComponent(this); + _playerComponent = new GamePlayerComponent(this); + _waterComponent = new GameWaterComponent(this); + _compassComponent = new GameCompassComponent(this); + _endComponent = new GameEndComponent(this); + } + + public final void setupGameWorld(File mapZip) + { + _gameWorld = new GameWorld(this, mapZip); + _gameWorld.loadWorld(); + } + + public final void setupMineplexWorld(MineplexWorld mineplexWorld) + { + _mineplexWorld = mineplexWorld; + + createTeams(); + parseData(); + + setState(GameState.Prepare); + } + + protected abstract void createTeams(); + + protected abstract void parseData(); + + public abstract boolean endGame(); + + public abstract void disable(); + + @Override + public final PhasedLifetime getLifetime() + { + return _lifetime; + } + + @Override + public final void deactivate() + { + disable(); + + super.deactivate(); + + AntiHack antiHack = _manager.getAntiHack(); + antiHack.resetIgnoredChecks(); + } + + public final NanoManager getManager() + { + return _manager; + } + + public final GameType getGameType() + { + return _gameType; + } + + public final String[] getDescription() + { + return _description; + } + + public GameWorld getGameWorld() + { + return _gameWorld; + } + + public final MineplexWorld getMineplexWorld() + { + return _mineplexWorld; + } + + public final void setState(GameState state) + { + _lifetime.setPhase(state); + + _manager.log("Game State set to " + state); + UtilServer.CallEvent(new GameStateChangeEvent(this, state)); + + _stateTime = System.currentTimeMillis(); + } + + public final GameState getState() + { + return _lifetime.getPhase(); + } + + public final boolean isLive() + { + return getState() == GameState.Live; + } + + public final boolean inProgress() + { + return getState() == GameState.Prepare || isLive(); + } + + public final long getStateTime() + { + return _stateTime; + } + + public void announce(String message) + { + announce(message, Sound.NOTE_PLING); + } + + public void announce(String message, Sound sound) + { + Bukkit.broadcastMessage(message); + + if (sound != null) + { + for (Player player : UtilServer.getPlayersCollection()) + { + player.playSound(player.getLocation(), sound, 1, 1); + } + } + } + + /* + Teams + */ + + @Override + public GameTeam addTeam(GameTeam gameTeam) + { + return _teamComponent.addTeam(gameTeam); + } + + @Override + public List getTeams() + { + return _teamComponent.getTeams(); + } + + @Override + public void joinTeam(Player player, GameTeam team) + { + _teamComponent.joinTeam(player, team); + } + + @Override + public GameTeam getTeam(Player player) + { + return _teamComponent.getTeam(player); + } + + @Override + public boolean isAlive(Player player) + { + return _teamComponent.isAlive(player); + } + + @Override + public void respawnPlayer(Player player, GameTeam team) + { + _teamComponent.respawnPlayer(player, team); + } + + @Override + public boolean hasRespawned(Player player) + { + return _teamComponent.hasRespawned(player); + } + + @Override + public List getAllPlayers() + { + return _teamComponent.getAllPlayers(); + } + + @Override + public List getAlivePlayers() + { + return _teamComponent.getAlivePlayers(); + } + + /* + Spectator + */ + + @Override + public void addSpectator(Player player, boolean teleport, boolean out) + { + _spectatorComponent.addSpectator(player, teleport, out); + } + + @Override + public Location getSpectatorLocation() + { + return _spectatorComponent.getSpectatorLocation(); + } + + /* + Winners + */ + + public void setWinningTeam(GameTeam winningTeam) + { + _winningTeam = winningTeam; + } + + public GameTeam getWinningTeam() + { + return _winningTeam; + } + + public GamePlacements getGamePlacements() + { + if (_placements == null) + { + _placements = createPlacements(); + } + + return _placements; + } + + protected abstract GamePlacements createPlacements(); + + /* + Currency + */ + + @Override + public void addGems(Player player, int amount) + { + _manager.getCurrencyManager().addGems(player, amount); + } + + /* + Component Getters + */ + + public GameWorldComponent getWorldComponent() + { + return _worldComponent; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameComponent.java new file mode 100644 index 000000000..38f117289 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameComponent.java @@ -0,0 +1,51 @@ +package mineplex.game.nano.game; + +import java.util.Arrays; + +import mineplex.core.lifetimes.Lifetime; +import mineplex.core.lifetimes.Lifetimed; +import mineplex.core.lifetimes.ListenerComponent; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.components.Disposable; + +public abstract class GameComponent extends ListenerComponent implements Lifetimed, Disposable +{ + + private final Lifetime _lifetime; + private final T _game; + + public GameComponent(T game, GameState... active) + { + _game = game; + + if (active == null || active.length == 0) + { + // Active for the entire duration of the game. + _lifetime = game.getLifetime(); + _lifetime.register(this); + } + else + { + _lifetime = game.getLifetime().register(this, Arrays.asList(active)); + } + } + + @Override + public final void deactivate() + { + disable(); + + super.deactivate(); + } + + @Override + public Lifetime getLifetime() + { + return _lifetime; + } + + public T getGame() + { + return _game; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GamePlacements.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GamePlacements.java new file mode 100644 index 000000000..b69b7a5b2 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GamePlacements.java @@ -0,0 +1,58 @@ +package mineplex.game.nano.game; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import org.bukkit.entity.Player; + +public class GamePlacements +{ + + public static GamePlacements fromTeamPlacements(List players) + { + return new GamePlacements(players.stream() + .map(Collections::singletonList) + .collect(Collectors.toList())); + } + + public static GamePlacements fromPlayerScore(Map entries) + { + Map> sorted = new TreeMap<>(Comparator.reverseOrder()); + + entries.forEach((player, score) -> sorted.computeIfAbsent(score, k -> new ArrayList<>()).add(player)); + + return new GamePlacements(new ArrayList<>(sorted.values())); + } + + private final List> _placements; + + private GamePlacements(List> placements) + { + _placements = placements; + } + + public List getPlayersAtPlace(int position) + { + if (position < 0 || position >= _placements.size()) + { + return null; + } + + return _placements.get(position); + } + + public List getWinners() + { + return getPlayersAtPlace(0); + } + + public boolean hasPlacements() + { + return !_placements.isEmpty(); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameType.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameType.java new file mode 100644 index 000000000..feac79e57 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/GameType.java @@ -0,0 +1,101 @@ +package mineplex.game.nano.game; + +import java.io.File; + +import mineplex.core.game.GameDisplay; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.games.bawkbawk.BawkBawk; +import mineplex.game.nano.game.games.chickenshoot.ChickenShoot; +import mineplex.game.nano.game.games.colourchange.ColourChange; +import mineplex.game.nano.game.games.copycat.CopyCat; +import mineplex.game.nano.game.games.deathtag.DeathTag; +import mineplex.game.nano.game.games.findores.FindOres; +import mineplex.game.nano.game.games.jumprope.JumpRope; +import mineplex.game.nano.game.games.kingslime.KingSlime; +import mineplex.game.nano.game.games.microbattle.MicroBattle; +import mineplex.game.nano.game.games.mobfarm.MobFarm; +import mineplex.game.nano.game.games.musicminecart.MusicMinecarts; +import mineplex.game.nano.game.games.oits.SnowballTrouble; +import mineplex.game.nano.game.games.parkour.Parkour; +import mineplex.game.nano.game.games.quick.Quick; +import mineplex.game.nano.game.games.redgreenlight.RedGreenLight; +import mineplex.game.nano.game.games.slimecycles.SlimeCycles; +import mineplex.game.nano.game.games.spleef.Spleef; +import mineplex.game.nano.game.games.sploor.Sploor; +import mineplex.game.nano.game.games.tag.HotPotato; +import mineplex.game.nano.game.games.tag.ReverseTag; +import mineplex.game.nano.game.games.territory.Territory; + +public enum GameType +{ + + HOT_POTATO(HotPotato.class, "Hot Potato"), + REVERSE_TAG(ReverseTag.class, "Reverse Tag"), + MICRO_BATTLE(MicroBattle.class, "Nano Battle", mapsFromArcade(GameDisplay.Micro)), + DEATH_TAG(DeathTag.class, "Zombie Survival", mapsFromArcade(GameDisplay.DeathTag)), + RED_GREEN_LIGHT(RedGreenLight.class, "Red Light Green Light"), + COLOUR_CHANGE(ColourChange.class, "Color Swap"), + SPLOOR(Sploor.class, "Sploor"), + KING_SLIME(KingSlime.class, "King Slime"), + SPLEEF(Spleef.class, "AAAAAAAA! Spleef", mapsFromArcade(GameDisplay.Runner)), + JUMP_ROPE(JumpRope.class, "Jump Rope"), + FIND_ORES(FindOres.class, "Ores Ores Ores"), + MUSIC_MINECARTS(MusicMinecarts.class, "Musical Minecarts"), + MOB_FARM(MobFarm.class, "Mob Farm"), + CHICKEN_SHOOT(ChickenShoot.class, "Chicken Shoot", mapsFromNano("Mob Farm")), + SLIME_CYCLES(SlimeCycles.class, "Slime Cycles"), + TERRITORY(Territory.class, "Slime Territory"), + COPY_CAT(CopyCat.class, "Copy Cat"), + SNOWBALL_TROUBLE(SnowballTrouble.class, "Snowball Trouble", mapsFromArcade(GameDisplay.Quiver)), + PARKOUR(Parkour.class, "Hardcore Parkour"), + BAWK_BAWK(BawkBawk.class, "Bawk Bawk's Wrath"), + QUICK(Quick.class, "Quick") + + ; + + private static String maps() + { + return ".." + File.separator + ".." + File.separator + "update" + File.separator + "maps"; + } + + private static String mapsFromArcade(GameDisplay display) + { + return maps() + File.separator + display.getName(); + } + + private static String mapsFromNano(String name) + { + return mapsFromArcade(NanoManager.getGameDisplay()) + File.separator + name; + } + + private final Class _gameClass; + private final String _name; + private final String _mapDirectory; + + GameType(Class gameClass, String name) + { + this(gameClass, name, mapsFromNano(name)); + } + + GameType(Class gameClass, String name, String mapDirectory) + { + _gameClass = gameClass; + _name = name; + _mapDirectory = mapDirectory; + } + + public Class getGameClass() + { + return _gameClass; + } + + public String getName() + { + return _name; + } + + public String getMapDirectory() + { + return _mapDirectory; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/ScoredSoloGame.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/ScoredSoloGame.java new file mode 100644 index 000000000..7f39798ae --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/ScoredSoloGame.java @@ -0,0 +1,145 @@ +package mineplex.game.nano.game; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +public abstract class ScoredSoloGame extends SoloGame +{ + + private final Map _scores; + private List> _sortedPlaces; + + public ScoredSoloGame(NanoManager manager, GameType gameType, String[] description) + { + super(manager, gameType, description); + + _scores = new HashMap<>(); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Players"); + + if (getState() == GameState.Prepare || _sortedPlaces == null) + { + scoreboard.write(getAllPlayers().size() + " Players"); + } + else + { + scoreboard.writeNewLine(); + + List> sorted = _sortedPlaces; + boolean hasShownPlayer = false; + + for (int i = 0; i < Math.min(sorted.size(), hasShownPlayer ? 11 : 9); i++) + { + Entry entry = sorted.get(i); + Player other = entry.getKey(); + + if (player.equals(other)) + { + hasShownPlayer = true; + } + + scoreboard.write(entry.getValue() + " " + (player.equals(other) ? C.cGreen : (UtilPlayer.isSpectator(other) ? C.cGray + C.Strike : C.cYellow)) + other.getName()); + } + + if (!hasShownPlayer) + { + Entry entry = null; + + for (Entry other : sorted) + { + if (player.equals(other.getKey())) + { + entry = other; + break; + } + } + + if (entry != null) + { + scoreboard.writeNewLine(); + + scoreboard.write(entry.getValue() + " " + C.cGreen + player.getName()); + } + } + } + + scoreboard.writeNewLine(); + + scoreboard.draw(); + }); + } + + @Override + public void disable() + { + _scores.clear(); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + _scores.putIfAbsent(event.getPlayer(), 0); + } + + @EventHandler + public void playerOut(PlayerStateChangeEvent event) + { + if (!event.isAlive()) + { + _scores.remove(event.getPlayer()); + } + } + + public void incrementScore(Player player, int score) + { + if (player == null) + { + return; + } + + _scores.put(player, _scores.getOrDefault(player, 0) + score); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void updateScores(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive()) + { + return; + } + + _sortedPlaces = _scores.entrySet().stream() + .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) + .collect(Collectors.toList()); + } + + public Map getScores() + { + return _scores; + } + + @Override + protected GamePlacements createPlacements() + { + return GamePlacements.fromPlayerScore(_scores); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/SoloGame.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/SoloGame.java new file mode 100644 index 000000000..3a5a5fc5a --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/SoloGame.java @@ -0,0 +1,75 @@ +package mineplex.game.nano.game; + +import java.util.List; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import mineplex.core.common.util.C; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.components.team.GameTeam; + +public abstract class SoloGame extends Game +{ + + protected GameTeam _playersTeam; + + public SoloGame(NanoManager manager, GameType gameType, String[] description) + { + super(manager, gameType, description); + + _damageComponent.setTeamSelf(true); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + List alive = getAlivePlayers(); + scoreboard.write(C.cYellowB + "Players"); + + if (alive.size() > 11) + { + scoreboard.write(alive.size() + " Alive"); + } + else + { + alive.forEach(other -> scoreboard.write((other.equals(player) ? C.cGreen : "") + other.getName())); + } + + scoreboard.writeNewLine(); + + scoreboard.draw(); + }); + } + + @Override + protected void createTeams() + { + _playersTeam = addTeam(new GameTeam(this, "Players", ChatColor.YELLOW, Color.YELLOW, DyeColor.YELLOW, getPlayerTeamSpawns())); + } + + public GameTeam getPlayersTeam() + { + return _playersTeam; + } + + public List getPlayerTeamSpawns() + { + return _mineplexWorld.getGoldLocations("Green"); + } + + @Override + public boolean endGame() + { + return getAlivePlayers().size() <= 1; + } + + @Override + protected GamePlacements createPlacements() + { + return GamePlacements.fromTeamPlacements(_playersTeam.getPlaces(true)); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/TeamGame.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/TeamGame.java new file mode 100644 index 000000000..45ed883f0 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/TeamGame.java @@ -0,0 +1,62 @@ +package mineplex.game.nano.game; + +import java.util.ArrayList; + +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.components.end.GameEndComponent.AnnouncementType; +import mineplex.game.nano.game.components.team.GameTeam; + +public abstract class TeamGame extends Game +{ + + public TeamGame(NanoManager manager, GameType gameType, String[] description) + { + super(manager, gameType, description); + + _endComponent.setAnnouncementType(AnnouncementType.TEAM); + } + + @Override + public boolean endGame() + { + GameTeam aliveTeam = null; + int teamsAlive = 0; + + for (GameTeam team : getTeams()) + { + if (team.getAlivePlayers().isEmpty()) + { + continue; + } + + aliveTeam = team; + teamsAlive++; + } + + if (teamsAlive == 0) + { + return true; + } + else if (teamsAlive == 1) + { + setWinningTeam(aliveTeam); + return true; + } + + return false; + } + + @Override + protected GamePlacements createPlacements() + { + GameTeam winningTeam = getWinningTeam(); + + if (winningTeam == null) + { + return null; + } + + + return GamePlacements.fromTeamPlacements(new ArrayList<>(winningTeam.getAllPlayers())); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/ComponentHook.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/ComponentHook.java new file mode 100644 index 000000000..e5afbad02 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/ComponentHook.java @@ -0,0 +1,12 @@ +package mineplex.game.nano.game.components; + +import mineplex.game.nano.game.GameComponent; + +public interface ComponentHook +{ + + void setHook(T hook); + + T getHook(); + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/Disposable.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/Disposable.java new file mode 100644 index 000000000..ee7581427 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/Disposable.java @@ -0,0 +1,8 @@ +package mineplex.game.nano.game.components; + +public interface Disposable +{ + + void disable(); + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassComponent.java new file mode 100644 index 000000000..f41294302 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassComponent.java @@ -0,0 +1,145 @@ +package mineplex.game.nano.game.components.compass; + +import java.text.DecimalFormat; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.components.team.GameTeam; + +public class GameCompassComponent extends GameComponent +{ + + private static final ItemStack COMPASS = new ItemBuilder(Material.COMPASS) + .setTitle(C.cGreenB + "Tracking Compass") + .build(); + + private final GameCompassShop _shop; + private final DecimalFormat _distanceFormat = new DecimalFormat("0.0"); + + private boolean _giveToAlive; + + public GameCompassComponent(Game game) + { + super(game, GameState.Live); + + _shop = new GameCompassShop(this, game.getManager()); + } + + public GameCompassComponent setGiveToAlive(boolean giveToAlive) + { + _giveToAlive = giveToAlive; + return this; + } + + @Override + public void disable() + { + for (Player player : UtilServer.getPlayersCollection()) + { + player.getInventory().remove(COMPASS); + } + } + + @EventHandler + public void updateCompasses(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + for (Player player : UtilServer.getPlayersCollection()) + { + boolean alive = getGame().isAlive(player); + + if (!player.getInventory().contains(COMPASS) && (_giveToAlive || !alive)) + { + player.getInventory().addItem(COMPASS); + } + + if (COMPASS.equals(player.getItemInHand())) + { + Player closest; + + if (alive) + { + closest = UtilPlayer.getClosest(player.getLocation(), getGame().getTeam(player).getAlivePlayers()); + } + else + { + closest = UtilPlayer.getClosest(player.getLocation(), player); + } + + if (closest == null) + { + continue; + } + + GameTeam closestTeam = getGame().getTeam(closest); + + if (closestTeam == null) + { + continue; + } + + double dist = UtilMath.offset(player, closest); + + UtilTextBottom.display(C.cWhiteB + "Target: " + closestTeam.getChatColour() + closest.getName() + C.cWhiteB + " Distance: " + closestTeam.getChatColour() + _distanceFormat.format(dist), player); + } + } + } + + @EventHandler + public void playerInteract(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (!COMPASS.equals(itemStack) || getGame().isAlive(player)) + { + return; + } + + _shop.attemptShopOpen(player); + } + + @EventHandler(ignoreCancelled = true) + public void inventoryClick(InventoryClickEvent event) + { + UtilInv.DisallowMovementOf(event, COMPASS.getItemMeta().getDisplayName(), COMPASS.getType(), COMPASS.getData().getData(), true); + } + + @EventHandler(ignoreCancelled = true) + public void playerDropItem(PlayerDropItemEvent event) + { + if (event.getItemDrop().getItemStack().equals(COMPASS)) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassPage.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassPage.java new file mode 100644 index 000000000..98234f258 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassPage.java @@ -0,0 +1,55 @@ +package mineplex.game.nano.game.components.compass; + +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilMath; +import mineplex.core.donation.DonationManager; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.shop.page.ShopPageBase; +import mineplex.game.nano.game.components.team.GameTeam; + +public class GameCompassPage extends ShopPageBase +{ + + GameCompassPage(GameCompassComponent plugin, GameCompassShop shop, CoreClientManager clientManager, DonationManager donationManager, Player player) + { + super(plugin, shop, clientManager, donationManager, "Tracking Compass", player); + + buildPage(); + } + + @Override + protected void buildPage() + { + int slot = 0; + + for (GameTeam team : getPlugin().getGame().getTeams()) + { + for (Player target : team.getAlivePlayers()) + { + if (slot >= getSize()) + { + return; + } + + addButton(slot++, new ItemBuilder(Material.SKULL_ITEM, (byte) 3) + .setTitle(team.getChatColour() + target.getName()) + .setPlayerHead(target.getName()) + .addLore( + "", + "Distance: " + C.cWhite + (int) UtilMath.offset(getPlayer(), target), + "", + "Click to teleport to " + target.getName() + "!" + ) + .build(), (player, clickType) -> + { + player.closeInventory(); + player.teleport(target); + }); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassShop.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassShop.java new file mode 100644 index 000000000..a2536fddc --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/compass/GameCompassShop.java @@ -0,0 +1,22 @@ +package mineplex.game.nano.game.components.compass; + +import org.bukkit.entity.Player; + +import mineplex.core.shop.ShopBase; +import mineplex.core.shop.page.ShopPageBase; +import mineplex.game.nano.NanoManager; + +public class GameCompassShop extends ShopBase +{ + + GameCompassShop(GameCompassComponent plugin, NanoManager manager) + { + super(plugin, manager.getClientManager(), manager.getDonationManager(), "Game Compass"); + } + + @Override + protected ShopPageBase> buildPagesFor(Player player) + { + return new GameCompassPage(getPlugin(), this, getClientManager(),getDonationManager(), player); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/CurrencyComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/CurrencyComponent.java new file mode 100644 index 000000000..bb0752eff --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/CurrencyComponent.java @@ -0,0 +1,10 @@ +package mineplex.game.nano.game.components.currency; + +import org.bukkit.entity.Player; + +public interface CurrencyComponent +{ + + void addGems(Player player, int amount); + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/GameCurrencyManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/GameCurrencyManager.java new file mode 100644 index 000000000..34aa54463 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/currency/GameCurrencyManager.java @@ -0,0 +1,229 @@ +package mineplex.game.nano.game.components.currency; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.achievement.Achievement; +import mineplex.core.boosters.Booster; +import mineplex.core.command.CommandBase; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.C; +import mineplex.core.portal.events.GenericServerTransferEvent; +import mineplex.core.portal.events.ServerTransferEvent; +import mineplex.core.titles.tracks.TrackManager; +import mineplex.core.titles.tracks.standard.GemCollectorTrack; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class GameCurrencyManager extends GameManager implements CurrencyComponent +{ + + public enum Perm implements Permission + { + SHARD_MULT_1, + SHARD_MULT_2, + SHARD_MULT_3, + SHARD_MULT_4, + SHARD_MULT_5, + REWARDS_COMMAND + } + + private final Map _sessionData; + + private GameCurrencyManager() + { + super("Game Currency"); + + _sessionData = new HashMap<>(); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.ULTRA.setPermission(Perm.SHARD_MULT_1, true, true); + PermissionGroup.HERO.setPermission(Perm.SHARD_MULT_2, true, true); + PermissionGroup.LEGEND.setPermission(Perm.SHARD_MULT_3, true, true); + PermissionGroup.TITAN.setPermission(Perm.SHARD_MULT_4, true, true); + PermissionGroup.ETERNAL.setPermission(Perm.SHARD_MULT_5, true, true); + PermissionGroup.PLAYER.setPermission(Perm.REWARDS_COMMAND, true, true); + } + + @Override + public void addCommands() + { + addCommand(new CommandBase(this, Perm.REWARDS_COMMAND, "rewards") + { + @Override + public void Execute(Player caller, String[] args) + { + informRewards(caller, false); + } + }); + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + _sessionData.put(event.getPlayer(), new GameSessionData()); + } + + @EventHandler + public void gameEnd(GameStateChangeEvent event) + { + if (event.getState() != GameState.End) + { + return; + } + + for (Player player : event.getGame().getAllPlayers()) + { + GameSessionData data = _sessionData.get(player); + + if (data != null) + { + data.Games++; + } + } + } + + @Override + public void addGems(Player player, int amount) + { + GameSessionData data = _sessionData.get(player); + + if (data != null) + { + data.Gems += amount; + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void serverTransfer(ServerTransferEvent event) + { + informRewards(event.getPlayer(), true); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void serverTransfer(GenericServerTransferEvent event) + { + informRewards(event.getPlayer(), true); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void playerQuit(PlayerQuitEvent event) + { + informRewards(event.getPlayer(), true); + } + + private void informRewards(Player player, boolean reward) + { + GameSessionData data = _sessionData.get(player); + + if (data == null || data.Games == 0 || !_manager.getServerGroup().getRewardGems()) + { + return; + } + + CoreClient client = _manager.getClientManager().Get(player); + String gameName = NanoManager.getGameDisplay().getName(); + + int gems = data.Gems; + int shards = gems; + int exp = gems * 6; + + // Gem Hunter Bonus + int gemHunter = _manager.getAchievementManager().get(player, Achievement.GLOBAL_GEM_HUNTER).getLevel(); + + if (gemHunter > 0) + { + gems += (int) (gems * (gemHunter * 0.25D)); + } + + // Shard Amplifier Bonus + Booster booster = _manager.getBoosterManager().getActiveBooster(); + + if (booster != null) + { + shards *= booster.getMultiplier(); + } + + // Shard Rank Bonus + double shardMultiplier = 1; + + for (Perm shardMultPerm : Perm.values()) + { + if (client.hasPermission(shardMultPerm)) + { + shardMultiplier += 0.5; + } + } + + shards *= shardMultiplier; + + // Award + if (reward) + { + if (_manager.getServerGroup().getRewardGems()) + { + _manager.getDonationManager().rewardCurrencyUntilSuccess(GlobalCurrency.GEM, player, "Earned " + gameName, gems, null); + _manager.getDonationManager().rewardCurrencyUntilSuccess(GlobalCurrency.TREASURE_SHARD, player, "Earned", shards, null); + } + + if (_manager.getServerGroup().getRewardStats()) + { + // TODO enable game specific stats after beta + _manager.getStatsManager().incrementStat(player, "Global.GemsEarned", gems); + //_manager.getStatsManager().incrementStat(player, gameName + ".GemsEarned", gems); + _manager.getStatsManager().incrementStat(player, "Global.ExpEarned", exp); + //_manager.getStatsManager().incrementStat(player, gameName + ".ExpEarned", exp); + _manager.getStatsManager().incrementStat(player, "Global.GamesPlayed", data.Games); + //_manager.getStatsManager().incrementStat(player, gameName + ".GamesPlayed", data.Games); + require(TrackManager.class).getTrack(GemCollectorTrack.class).earnedGems(player, gems); + } + + // Remove from session + _sessionData.remove(player); + } + + // Inform + player.sendMessage(NanoManager.getHeaderFooter()); + player.sendMessage(C.Bold + "Game Rewards"); + player.sendMessage(""); + player.sendMessage(" " + C.cGray + "Games Played: " + C.cYellow + data.Games); + + if (_manager.getServerGroup().getRewardGems()) + { + player.sendMessage(" " + C.cGray + "+" + C.cGreen + gems + C.cGray + " Gems"); + player.sendMessage(" " + C.cGray + "+" + C.cAqua + shards + C.cGray + " Shards"); + } + + if (_manager.getServerGroup().getRewardStats()) + { + player.sendMessage(" " + C.cGray + "+" + C.cYellow + exp + C.cGray + " Experience"); + } + + player.sendMessage(""); + player.sendMessage(NanoManager.getHeaderFooter()); player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, 0.4F); + } + + private class GameSessionData + { + int Gems; + int Games; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageComponent.java new file mode 100644 index 000000000..99650da70 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageComponent.java @@ -0,0 +1,78 @@ +package mineplex.game.nano.game.components.damage; + +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.GameComponent; + +public class GameDamageComponent extends GameComponent +{ + + private boolean _damage = true, _pvp = true, _fall = true, _self = true, _teamSelf = false; + + public GameDamageComponent(Game game) + { + super(game); + + game.getManager().getGameDamageManager().setHook(this); + } + + @Override + public void disable() + { + + } + + public GameDamageComponent setDamage(boolean damage) + { + _damage = damage; + return this; + } + + public boolean isDamageEnabled() + { + return _damage; + } + + public GameDamageComponent setPvp(boolean pvp) + { + _pvp = pvp; + return this; + } + + public boolean isPvpEnabled() + { + return _pvp; + } + + public GameDamageComponent setFall(boolean fall) + { + _fall = fall; + return this; + } + + public boolean isFallEnabled() + { + return _fall; + } + + public GameDamageComponent setSelf(boolean self) + { + _self = self; + return this; + } + + public boolean isSelfEnabled() + { + return _self; + } + + public GameDamageComponent setTeamSelf(boolean teamSelf) + { + _teamSelf = teamSelf; + return this; + } + + public boolean isTeamSelfEnabled() + { + return _teamSelf; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageManager.java new file mode 100644 index 000000000..89c0f3947 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/damage/GameDamageManager.java @@ -0,0 +1,127 @@ +package mineplex.game.nano.game.components.damage; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.UtilPlayer; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.components.ComponentHook; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.minecraft.game.core.combat.CombatLog; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +@ReflectivelyCreateMiniPlugin +public class GameDamageManager extends GameManager implements ComponentHook +{ + + private GameDamageComponent _hook; + + private GameDamageManager() + { + super("Damage Hook"); + } + + @Override + public void setHook(GameDamageComponent hook) + { + _hook = hook; + } + + @Override + public GameDamageComponent getHook() + { + return _hook; + } + + @EventHandler + public void gameDeath(GameStateChangeEvent event) + { + if (event.getState() == GameState.Dead) + { + setHook(null); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void damage(CustomDamageEvent event) + { + if (_hook == null) + { + event.SetCancelled("No Damage Hook"); + return; + } + else if (!_hook.getGame().isLive()) + { + event.SetCancelled("Game Not Live"); + } + + if (!_hook.isDamageEnabled()) + { + event.SetCancelled("Damage Disabled"); + } + else if (event.GetCause() == DamageCause.FALL && !_hook.isFallEnabled()) + { + event.SetCancelled("Fall Disabled"); + } + + Player damageePlayer = event.GetDamageePlayer(); + Player damagerPlayer = event.GetDamagerPlayer(true); + + if (UtilPlayer.isSpectator(damageePlayer) || UtilPlayer.isSpectator(damagerPlayer)) + { + event.SetCancelled("Spectator"); + } + + if (damageePlayer != null) + { + if (UtilPlayer.isSpectator(damageePlayer)) + { + damageePlayer.setFireTicks(0); + } + + if (damagerPlayer != null && !_manager.canHurt(damageePlayer, damagerPlayer)) + { + event.SetCancelled("PVP Disabled"); + } + } + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + if (_hook == null) + { + return; + } + + Player player = event.GetEvent().getEntity(); + GameTeam team = _hook.getGame().getTeam(player); + CombatLog log = event.GetLog(); + + if (team != null) + { + log.SetKilledColor(team.getChatColour().toString()); + } + + if (log.GetKiller() != null) + { + Player killer = UtilPlayer.searchExact(log.GetKiller().getUniqueIdOfEntity()); + + if (killer != null) + { + GameTeam killerTeam = _hook.getGame().getTeam(killer); + + if (killerTeam != null) + { + log.SetKillerColor(killerTeam.getChatColour().toString()); + } + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/end/GameEndComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/end/GameEndComponent.java new file mode 100644 index 000000000..72c548924 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/end/GameEndComponent.java @@ -0,0 +1,258 @@ +package mineplex.game.nano.game.components.end; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextTop; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.GamePlacements; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.GameTimeoutEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +public class GameEndComponent extends GameComponent +{ + + public enum AnnouncementType + { + SOLO, + TEAM + } + + private AnnouncementType _announcementType = AnnouncementType.SOLO; + private long _winEffectTime = TimeUnit.SECONDS.toMillis(4); + private long _timeout = TimeUnit.MINUTES.toMillis(4); + + public GameEndComponent(Game game) + { + super(game, GameState.Live, GameState.End); + } + + public GameEndComponent setAnnouncementType(AnnouncementType announcementType) + { + _announcementType = announcementType; + return this; + } + + public GameEndComponent setWinEffectTime(long winEffectTime) + { + _winEffectTime = winEffectTime; + return this; + } + + public GameEndComponent setTimeout(long timeout) + { + _timeout = timeout; + return this; + } + + @Override + public void disable() + { + + } + + @EventHandler(priority = EventPriority.MONITOR) + public void playerOut(PlayerStateChangeEvent event) + { + if (getGame().isLive() && getGame().endGame()) + { + getGame().setState(GameState.End); + } + } + + @EventHandler + public void updateTimeout(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !getGame().isLive() || _timeout < 0) + { + return; + } + + if (UtilTime.elapsed(getGame().getStateTime(), _timeout)) + { + UtilServer.CallEvent(new GameTimeoutEvent(getGame())); + getGame().setState(GameState.End); + } + else + { + long diff = System.currentTimeMillis() - getGame().getStateTime(); + UtilTextTop.displayProgress(C.mTime + UtilTime.MakeStr(_timeout - diff), 1 - (double) diff / _timeout, UtilServer.getPlayers()); + } + } + + @EventHandler + public void end(GameStateChangeEvent event) + { + if (event.getState() != GameState.End) + { + return; + } + + announceEnd(); + + List winners = getGame().getGamePlacements() == null ? Collections.emptyList() : getGame().getGamePlacements().getWinners(); + + getGame().getManager().runSyncTimer(new BukkitRunnable() + { + @Override + public void run() + { + if (getGame().getState() != GameState.End || UtilTime.elapsed(getGame().getStateTime(), _winEffectTime)) + { + cancel(); + getGame().setState(GameState.Dead); + return; + } + + Player player = UtilAlg.Random(winners); + + if (player != null) + { + GameTeam team = getGame().getTeam(player); + + if (team == null) + { + return; + } + + Location location = UtilAlg.getRandomLocation(player.getLocation().add(0, 20, 0), 10, 3, 10); + + UtilFirework.playFirework(location, FireworkEffect.builder() + .with(Type.BALL_LARGE) + .withColor(team.getColour()) + .withFade(Color.WHITE) + .build()); + } + } + }, 0, 10); + } + + private void announceEnd() + { + for (Player player : UtilServer.getPlayersCollection()) + { + player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, 1); + } + + for (Player player : getGame().getAllPlayers()) + { + getGame().addGems(player, 10); + } + + Bukkit.broadcastMessage(NanoManager.getHeaderFooter()); + + Bukkit.broadcastMessage(C.cGreen + "Game - " + C.cYellowB + getGame().getGameType().getName()); + Bukkit.broadcastMessage(""); + + switch (_announcementType) + { + case SOLO: + announceSolo(); + break; + case TEAM: + announceTeam(); + break; + } + + Bukkit.broadcastMessage(""); + Bukkit.broadcastMessage(getGame().getMineplexWorld().getFormattedName()); + + Bukkit.broadcastMessage(NanoManager.getHeaderFooter()); + } + + private void announceSolo() + { + GamePlacements placements = getGame().getGamePlacements(); + + if (placements == null || !placements.hasPlacements()) + { + announceNobody(); + return; + } + + List first = placements.getPlayersAtPlace(0), second = placements.getPlayersAtPlace(1), third = placements.getPlayersAtPlace(2); + + Bukkit.broadcastMessage(C.cRedB + "1st Place " + C.cWhite + buildPlacementLine(first)); + first.forEach(player -> getGame().addGems(player, 20)); + + if (second != null) + { + Bukkit.broadcastMessage(C.cGoldB + "2nd Place " + C.cWhite + buildPlacementLine(second)); + second.forEach(player -> getGame().addGems(player, 15)); + } + + if (third != null) + { + Bukkit.broadcastMessage(C.cYellowB + "3rd Place " + C.cWhite + buildPlacementLine(third)); + third.forEach(player -> getGame().addGems(player, 10)); + } + } + + private String buildPlacementLine(List places) + { + if (places == null || places.isEmpty()) + { + return null; + } + + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < places.size() - 1; i++) + { + builder.append(places.get(i).getName()).append(", "); + } + + return builder + .append(places.get(places.size() - 1).getName()) + .toString(); + } + + private void announceTeam() + { + GameTeam winner = getGame().getWinningTeam(); + + Bukkit.broadcastMessage(""); + + if (winner == null) + { + announceNobody(); + } + else + { + Bukkit.broadcastMessage(" " + winner.getChatColour() + C.Bold + winner.getName() + " won the game!"); + + winner.getAllPlayers().forEach(player -> getGame().addGems(player, 20)); + } + + Bukkit.broadcastMessage(""); + } + + private void announceNobody() + { + Bukkit.broadcastMessage(C.cWhiteB + " Nobody won the game..."); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerComponent.java new file mode 100644 index 000000000..05acf7ad3 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerComponent.java @@ -0,0 +1,82 @@ +package mineplex.game.nano.game.components.player; + +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.GameComponent; + +public class GamePlayerComponent extends GameComponent +{ + + private boolean _hunger; + private boolean _regainHealth = true; + private boolean _itemMovement; + private boolean _itemDropPickup; + private boolean _hideParticles; + + public GamePlayerComponent(Game game) + { + super(game); + + game.getManager().getGamePlayerManager().setHook(this); + } + + @Override + public void disable() + { + + } + + public GamePlayerComponent setHunger(boolean hunger) + { + _hunger = hunger; + return this; + } + + public boolean isHunger() + { + return _hunger; + } + + public GamePlayerComponent setRegainHealth(boolean regainHealth) + { + _regainHealth = regainHealth; + return this; + } + + public boolean isRegainHealth() + { + return _regainHealth; + } + + public GamePlayerComponent setItemMovement(boolean itemMovement) + { + _itemMovement = itemMovement; + return this; + } + + public boolean isItemMovement() + { + return _itemMovement; + } + + public GamePlayerComponent setItemDropPickup(boolean itemDropPickup) + { + _itemDropPickup = itemDropPickup; + return this; + } + + public boolean isItemDropPickup() + { + return _itemDropPickup; + } + + public GamePlayerComponent setHideParticles(boolean hideParticles) + { + _hideParticles = hideParticles; + return this; + } + + public boolean isHideParticles() + { + return _hideParticles; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerManager.java new file mode 100644 index 000000000..cc32e7ddd --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GamePlayerManager.java @@ -0,0 +1,183 @@ +package mineplex.game.nano.game.components.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.teleport.event.MineplexTeleportEvent; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.components.ComponentHook; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class GamePlayerManager extends GameManager implements ComponentHook +{ + + public enum Perm implements Permission + { + ALLOW_TELEPORTS_IN_GAME + } + + private GamePlayerComponent _hook; + + private GamePlayerManager() + { + super("Player Hook"); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.ADMIN.setPermission(Perm.ALLOW_TELEPORTS_IN_GAME, true, true); + + if (UtilServer.isTestServer()) + { + PermissionGroup.QAT.setPermission(Perm.ALLOW_TELEPORTS_IN_GAME, true, true); + } + } + + @Override + public void setHook(GamePlayerComponent hook) + { + _hook = hook; + } + + @Override + public GamePlayerComponent getHook() + { + return _hook; + } + + @EventHandler(priority = EventPriority.HIGH) + public void gameState(GameStateChangeEvent event) + { + switch (event.getState()) + { + case Prepare: + _manager.getAntiHack().enableAnticheat(); + break; + case End: + _manager.getAntiHack().disableAnticheat(); + break; + case Dead: + setHook(null); + break; + + } + } + + @EventHandler(priority = EventPriority.LOW) + public void foodLevelChange(FoodLevelChangeEvent event) + { + if (_hook == null || !_hook.isHunger() || UtilPlayer.isSpectator(event.getEntity())) + { + event.setFoodLevel(20); + } + + if (event.getEntity() instanceof Player) + { + ((Player) event.getEntity()).setSaturation(3.8F); + } + } + + @EventHandler + public void regainHealth(EntityRegainHealthEvent event) + { + if (_hook == null || _hook.isRegainHealth() || event.getRegainReason() != RegainReason.SATIATED) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void inventoryClick(InventoryClickEvent event) + { + if (_hook == null || !_hook.isItemMovement()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void itemDrop(PlayerDropItemEvent event) + { + Player player = event.getPlayer(); + + if (_hook == null || !_hook.isItemDropPickup() || UtilPlayer.isSpectator(player)) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void itemPickup(PlayerPickupItemEvent event) + { + Player player = event.getPlayer(); + + if (_hook == null || !_hook.isItemDropPickup() || UtilPlayer.isSpectator(player)) + { + event.setCancelled(true); + } + } + + @EventHandler + public void entityCombust(EntityCombustEvent event) + { + if (_hook == null || UtilPlayer.isSpectator(event.getEntity())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void hideParticles(GameStateChangeEvent event) + { + if (_hook == null || event.getState() != GameState.Prepare) + { + return; + } + + _manager.getCosmeticManager().setHideParticles(_hook.isHideParticles()); + _manager.getCosmeticManager().getGadgetManager().disableAll(); + } + + @EventHandler + public void vehicleEnter(VehicleEnterEvent event) + { + if (UtilPlayer.isSpectator(event.getEntered())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void playerTeleport(MineplexTeleportEvent event) + { + Player player = event.getPlayer(); + + if (_hook == null || !_hook.getGame().isAlive(player) || _manager.getClientManager().Get(player).hasPermission(Perm.ALLOW_TELEPORTS_IN_GAME)) + { + return; + } + + event.setCancelled(true); + _hook.getGame().addSpectator(player, false, true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GiveItemComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GiveItemComponent.java new file mode 100644 index 000000000..d0be504b5 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/GiveItemComponent.java @@ -0,0 +1,57 @@ +package mineplex.game.nano.game.components.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.ItemStack; + +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; + +public class GiveItemComponent extends GameComponent +{ + + private ItemStack[] _items, _armour; + + public GiveItemComponent(Game game) + { + super(game, GameState.Prepare, GameState.Live); + } + + @Override + public void disable() + { + _items = null; + _armour = null; + } + + public GiveItemComponent setItems(ItemStack[] items) + { + _items = items; + return this; + } + + public GiveItemComponent setArmour(ItemStack[] armour) + { + _armour = armour; + return this; + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + if (_items != null) + { + player.getInventory().clear(); + player.getInventory().addItem(_items); + } + + if (_armour != null) + { + player.getInventory().setArmorContents(_armour); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/NightVisionComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/NightVisionComponent.java new file mode 100644 index 000000000..3488472f8 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/player/NightVisionComponent.java @@ -0,0 +1,44 @@ +package mineplex.game.nano.game.components.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; + +public class NightVisionComponent extends GameComponent +{ + + public NightVisionComponent(Game game) + { + super(game, GameState.Prepare, GameState.Live, GameState.End); + } + + @Override + public void disable() + { + + } + + @EventHandler + public void giveNightVision(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + for (Player player : getGame().getMineplexWorld().getWorld().getPlayers()) + { + if (!player.hasPotionEffect(PotionEffectType.NIGHT_VISION)) + { + player.addPotionEffect(new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, false, false)); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/prepare/GamePrepareComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/prepare/GamePrepareComponent.java new file mode 100644 index 000000000..1b3f8de44 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/prepare/GamePrepareComponent.java @@ -0,0 +1,205 @@ +package mineplex.game.nano.game.components.prepare; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTextTop; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +public class GamePrepareComponent extends GameComponent +{ + + private long _prepareTime = TimeUnit.SECONDS.toMillis(10); + private boolean _prepareFreeze = true; + + private boolean _colourTick; + + public GamePrepareComponent(Game game) + { + super(game, GameState.Prepare); + } + + public GamePrepareComponent setPrepareTime(long prepareTime) + { + _prepareTime = prepareTime; + return this; + } + + public GamePrepareComponent setPrepareFreeze(boolean prepareFreeze) + { + _prepareFreeze = prepareFreeze; + return this; + } + + @Override + public void disable() + { + + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + announceGame(); + + getGame().getManager().runSyncTimer(new BukkitRunnable() + { + int ticks = 0; + int messageIndex = -1; + + @Override + public void run() + { + if (getGame().getState() != GameState.Prepare) + { + cancel(); + return; + } + + long diff = System.currentTimeMillis() - getGame().getStateTime(); + + if (diff > _prepareTime) + { + cancel(); + + if (getGame().getAllPlayers().size() > 1) + { + announceStart(); + getGame().setState(GameState.Live); + } + else + { + getGame().setState(GameState.Dead); + } + } + else + { + Player[] players = UtilServer.getPlayers(); + + if (ticks % 20 == 0) + { + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.NOTE_STICKS, 1, 1); + } + } + + if (ticks % 40 == 0 && messageIndex < getGame().getDescription().length) + { + String title = C.cYellowB + getGame().getGameType().getName(); + + if (messageIndex == -1) + { + UtilTextMiddle.display(title, null, 0, 45, 0, players); + } + else + { + UtilTextMiddle.display(title, getGame().getDescription()[messageIndex], 0, 45, 0, players); + } + + messageIndex++; + } + + UtilTextBottom.displayProgress("Game Start", (double) diff / _prepareTime, UtilTime.MakeStr(Math.max(0, _prepareTime - diff)), players); + ticks++; + } + } + }, 0, 1); + } + + @EventHandler(ignoreCancelled = true) + public void playerMove(PlayerMoveEvent event) + { + if (!_prepareFreeze || !getGame().isAlive(event.getPlayer())) + { + return; + } + + Location from = event.getFrom(), to = event.getTo(); + + if (from.getX() == to.getX() && from.getZ() == to.getZ()) + { + return; + } + + event.setTo(from); + } + + @EventHandler + public void updateBossBar(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + UtilTextTop.display((_colourTick ? C.cGoldB : C.cWhiteB) + "MINEPLEX.COM" + C.cGrayB + " - " + (_colourTick ? C.cWhiteB : C.cGoldB) + "NANO GAMES", UtilServer.getPlayers()); + _colourTick = !_colourTick; + } + + private void announceGame() + { + String[] description = getGame().getDescription(); + + for (Player player : UtilServer.getPlayersCollection()) + { + player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, 1); + } + + for (int i = 0; i < 6 - description.length; i++) + { + Bukkit.broadcastMessage(""); + } + + Bukkit.broadcastMessage(NanoManager.getHeaderFooter()); + + Bukkit.broadcastMessage(C.cGreen + "Game - " + C.cYellowB + getGame().getGameType().getName()); + Bukkit.broadcastMessage(""); + + for (String line : description) + { + Bukkit.broadcastMessage(C.cWhite + " " + line); + } + + Bukkit.broadcastMessage(""); + Bukkit.broadcastMessage(getGame().getMineplexWorld().getFormattedName()); + + Bukkit.broadcastMessage(NanoManager.getHeaderFooter()); + + getGame().getManager().getChat().setChatSilence(_prepareTime, false); + } + + private void announceStart() + { + Player[] players = UtilServer.getPlayers(); + UtilTextBottom.display(C.cGreenB + "Start!", players); + + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/GameScoreboardComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/GameScoreboardComponent.java new file mode 100644 index 000000000..05b93273c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/GameScoreboardComponent.java @@ -0,0 +1,245 @@ +package mineplex.game.nano.game.components.scoreboard; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.TriConsumer; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilServer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class GameScoreboardComponent extends GameComponent +{ + + private final Map _scoreboard; + + private BiConsumer _scoreboardConsumer; + private BiFunction _prefixFunction; + private BiFunction _suffixFunction; + private TriConsumer _setupSettingsConsumer; + private BiFunction _tabListFunction; + private String _underNameObjective; + private BiFunction _underNameFunction; + + public GameScoreboardComponent(Game game) + { + super(game); + + _scoreboard = new HashMap<>(); + setPrefix((viewer, team) -> team.getChatColour().toString()); + } + + @Override + public void disable() + { + _scoreboard.clear(); + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + setupScoreboard(event.getPlayer(), true); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + for (Player player : UtilServer.getPlayersCollection()) + { + setupScoreboard(player, false); + } + + for (Player player : getGame().getManager().getSpectators()) + { + _scoreboard.values().forEach(scoreboard -> + { + scoreboard.setPlayerTeam(player, null); + scoreboard.refreshAsSubject(player); + }); + } + } + + private void setupScoreboard(Player player, boolean forceUpdate) + { + NanoScoreboard scoreboard = _scoreboard.computeIfAbsent(player, k -> new NanoScoreboard(this, player)); + player.setScoreboard(scoreboard.getHandle()); + + if (forceUpdate) + { + for (Player other : UtilServer.getPlayersCollection()) + { + scoreboard.setPlayerTeam(other, getGame().getTeam(other)); + scoreboard.refreshAsSubject(other); + } + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + String entry = player.getName(); + + _scoreboard.remove(player); + _scoreboard.values().forEach(scoreboard -> + { + Team team = scoreboard.getHandle().getEntryTeam(entry); + + if (team != null) + { + team.removeEntry(entry); + } + }); + } + + @EventHandler + public void dead(GameStateChangeEvent event) + { + if (event.getState() != GameState.Dead) + { + return; + } + + Scoreboard main = Bukkit.getScoreboardManager().getMainScoreboard(); + + for (Player player : UtilServer.getPlayersCollection()) + { + player.setScoreboard(main); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void updateSidebar(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || _scoreboardConsumer == null) + { + return; + } + + _scoreboard.forEach((player, scoreboard) -> _scoreboardConsumer.accept(player, scoreboard)); + } + + @EventHandler + public void updateTitle(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + _scoreboard.values().forEach(NanoScoreboard::updateTitle); + } + + @EventHandler + public void playerStateChange(PlayerStateChangeEvent event) + { + setPlayerTeam(event.getPlayer(), event.getTeam()); + } + + private void setPlayerTeam(Player subject, GameTeam team) + { + _scoreboard.values().forEach(scoreboard -> scoreboard.setPlayerTeam(subject, team)); + } + + public void refreshAsSubject(Player subject) + { + _scoreboard.values().forEach(scoreboard -> scoreboard.refreshAsSubject(subject)); + } + + public GameScoreboardComponent setSidebar(BiConsumer consumer) + { + _scoreboardConsumer = consumer; + return this; + } + + public GameScoreboardComponent setPrefix(BiFunction function) + { + _prefixFunction = function; + return this; + } + + public GameScoreboardComponent setSuffix(BiFunction function) + { + _suffixFunction = function; + return this; + } + + public GameScoreboardComponent setTabList(BiFunction function) + { + _tabListFunction = function; + return this; + } + + public GameScoreboardComponent setUnderNameObjective(String name) + { + _underNameObjective = name; + return this; + } + + public GameScoreboardComponent setUnderName(BiFunction function) + { + _underNameFunction = function; + return this; + } + + public GameScoreboardComponent setSetupSettingsConsumer(TriConsumer setupSettingsConsumer) + { + _setupSettingsConsumer = setupSettingsConsumer; + return this; + } + + public String getPrefix(Player viewer, GameTeam gameTeam) + { + return _prefixFunction == null ? C.Reset : _prefixFunction.apply(viewer, gameTeam); + } + + public String getSuffix(Player viewer, GameTeam gameTeam) + { + return _suffixFunction == null ? C.Reset : _suffixFunction.apply(viewer, gameTeam); + } + + public Integer getTabList(Player viewer, Player subject) + { + return _tabListFunction == null ? null : _tabListFunction.apply(viewer, subject); + } + + public String getUnderNameObjective() + { + return _underNameObjective; + } + + public Integer getUnderName(Player viewer, Player subject) + { + return _underNameFunction == null ? null : _underNameFunction.apply(viewer, subject); + } + + public TriConsumer getSetupSettingsConsumer() + { + return _setupSettingsConsumer; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/NanoScoreboard.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/NanoScoreboard.java new file mode 100644 index 000000000..b84f9efbe --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/scoreboard/NanoScoreboard.java @@ -0,0 +1,163 @@ +package mineplex.game.nano.game.components.scoreboard; + +import net.md_5.bungee.api.ChatColor; + +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +import mineplex.core.common.util.C; +import mineplex.core.scoreboard.WritableMineplexScoreboard; +import mineplex.core.titles.tracks.custom.ScrollAnimation; +import mineplex.game.nano.game.components.team.GameTeam; + +public class NanoScoreboard extends WritableMineplexScoreboard +{ + + private static final String[] TITLE = new ScrollAnimation(" MINEPLEX ") + .withPrimaryColour(ChatColor.GOLD) + .withSecondaryColour(ChatColor.YELLOW) + .withTertiaryColour(ChatColor.WHITE) + .bold() + .build(); + private static final String SPEC_TEAM = "SPEC"; + + private final GameScoreboardComponent _manager; + + private int _shineIndex; + + NanoScoreboard(GameScoreboardComponent manager, Player player) + { + super(player); + + _manager = manager; + setSidebarName(TITLE[0]); + } + + @Override + public void draw() + { + while (_bufferedLines.size() > 15) + { + _bufferedLines.remove(_bufferedLines.size() - 1); + } + + super.draw(); + } + + void updateTitle() + { + setSidebarName(TITLE[_shineIndex]); + _shineIndex = (_shineIndex + 1) % TITLE.length; + } + + void refreshAsSubject(Player player) + { + updateTabList(player); + updateUnderName(player); + } + + void setPlayerTeam(Player subject, GameTeam team) + { + if (team == null) + { + setSpectating(subject); + return; + } + + String teamId = team.getName(); + Team scoreboardTeam = getHandle().getTeam(teamId); + + if (scoreboardTeam == null) + { + scoreboardTeam = getHandle().registerNewTeam(teamId); + scoreboardTeam.setPrefix(_manager.getPrefix(getOwner(), team)); + scoreboardTeam.setSuffix(_manager.getSuffix(getOwner(), team)); + + if (_manager.getSetupSettingsConsumer() != null) + { + _manager.getSetupSettingsConsumer().accept(getOwner(), team, scoreboardTeam); + } + } + + setPlayerTeam(subject, teamId); + } + + private void setSpectating(Player subject) + { + Team specTeam = getHandle().getTeam(SPEC_TEAM); + + if (specTeam == null) + { + specTeam = getHandle().registerNewTeam(SPEC_TEAM); + specTeam.setPrefix(C.cGray); + } + + setPlayerTeam(subject, SPEC_TEAM); + } + + private void setPlayerTeam(Player subject, String teamId) + { + String entry = subject.getName(); + + for (Team team : getHandle().getTeams()) + { + team.removeEntry(entry); + } + + getHandle().getTeam(teamId).addEntry(entry); + } + + private void updateTabList(Player subject) + { + Integer value = _manager.getTabList(getOwner(), subject); + + if (value == null) + { + return; + } + + Objective objective = getHandle().getObjective(DisplaySlot.PLAYER_LIST); + + if (objective == null) + { + objective = getHandle().registerNewObjective("TabList", "dummy"); + objective.setDisplaySlot(DisplaySlot.PLAYER_LIST); + } + + Score score = objective.getScore(subject.getName()); + + if (score.getScore() != value) + { + score.setScore(value); + } + } + + private void updateUnderName(Player subject) + { + if (_manager.getUnderNameObjective() == null) + { + return; + } + + Scoreboard handle = getHandle(); + Objective objective = handle.getObjective(DisplaySlot.BELOW_NAME); + int value = _manager.getUnderName(getOwner(), subject); + + if (objective == null) + { + objective = handle.registerNewObjective(_manager.getUnderNameObjective(), "dummy"); + objective.setDisplaySlot(DisplaySlot.BELOW_NAME); + } + + Score score = objective.getScore(subject.getName()); + + if (score.getScore() != value) + { + score.setScore(value); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/GameSpectatorComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/GameSpectatorComponent.java new file mode 100644 index 000000000..46284b577 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/GameSpectatorComponent.java @@ -0,0 +1,153 @@ +package mineplex.game.nano.game.components.spectator; + +import java.util.stream.Collectors; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerJoinEvent; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.game.nano.NanoPlayer; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.PlayerDeathOutEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +public class GameSpectatorComponent extends GameComponent implements SpectatorComponent +{ + + private boolean _deathOut = true; + private Location _spectatorLocation; + + public GameSpectatorComponent(Game game) + { + super(game); + } + + public GameSpectatorComponent setDeathOut(boolean deathOut) + { + _deathOut = deathOut; + return this; + } + + @Override + public void disable() + { + _spectatorLocation = null; + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void playerDeath(PlayerDeathEvent event) + { + Player player = event.getEntity(); + + event.getDrops().clear(); + + GameTeam team = getGame().getTeam(player); + + if (team == null) + { + return; + } + + // Prevent death + player.setMaxHealth(20); + player.setHealth(player.getMaxHealth()); + + if (_deathOut || !getGame().isLive()) + { + PlayerDeathOutEvent deathOutEvent = new PlayerDeathOutEvent(player); + UtilServer.CallEvent(deathOutEvent); + + if (deathOutEvent.isCancelled()) + { + if (deathOutEvent.shouldRespawn()) + { + getGame().respawnPlayer(player, team); + } + + return; + } + + Location location = player.getLocation(); + boolean teleport = location.getY() < getGame().getMineplexWorld().getMin().getY() || location.getBlock().isLiquid(); + + addSpectator(player, teleport, true); + + UtilTextMiddle.display(C.cRed + "You Died", "Don't quit! A new game will start shortly.", 0, 60, 20, player); + } + else + { + getGame().respawnPlayer(player, team); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void playerJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + + getGame().addSpectator(player, true, false); + UtilTextMiddle.display(C.cYellow + "Spectator", "You will join the next game!", 0, 60, 0, player); + } + + @Override + public void addSpectator(Player player, boolean teleport, boolean out) + { + if (out) + { + GameTeam team = getGame().getTeam(player); + + if (team != null) + { + team.setPlayerAlive(player, false); + } + else + { + UtilServer.CallEvent(new PlayerStateChangeEvent(player, null, false)); + } + } + + NanoPlayer.clear(getGame().getManager(), player); + + // Make them invisible + NanoPlayer.setSpectating(player, true); + getGame().getManager().getConditionManager().Factory().Cloak("Spectator", player, player, Integer.MAX_VALUE, true, true); + + // Flight + player.setAllowFlight(true); + player.setFlying(true); + + if (teleport) + { + player.teleport(getSpectatorLocation()); + } + } + + @Override + public Location getSpectatorLocation() + { + if (_spectatorLocation == null) + { + if (getGame().getTeams().isEmpty()) + { + _spectatorLocation = new Location(getGame().getMineplexWorld().getWorld(), 0, 100, 0); + } + else + { + _spectatorLocation = UtilAlg.getAverageLocation(getGame().getTeams().stream() + .flatMap(team -> team.getSpawns().stream()) + .collect(Collectors.toList())).add(0, 3, 0); + } + } + + return _spectatorLocation; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/SpectatorComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/SpectatorComponent.java new file mode 100644 index 000000000..f430bef5c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/spectator/SpectatorComponent.java @@ -0,0 +1,13 @@ +package mineplex.game.nano.game.components.spectator; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface SpectatorComponent +{ + + void addSpectator(Player player, boolean teleport, boolean out); + + Location getSpectatorLocation(); + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeam.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeam.java new file mode 100644 index 000000000..9c56e5f97 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeam.java @@ -0,0 +1,179 @@ +package mineplex.game.nano.game.components.team; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +public class GameTeam +{ + + private final Game _game; + private final String _name; + private final ChatColor _chatColour; + private final Color _colour; + private final DyeColor _dyeColour; + private final List _spawns; + + private final Map _players; + private final LinkedList _places; + + private int _overflowIndex; + + public GameTeam(Game game, String name, ChatColor chatColour, Color colour, DyeColor dyeColour, MineplexWorld mineplexWorld) + { + this(game, name, chatColour, colour, dyeColour, mineplexWorld.getGoldLocations(name)); + } + + public GameTeam(Game game, String name, ChatColor chatColour, Color colour, DyeColor dyeColour, List spawns) + { + _game = game; + _name = name; + _chatColour = chatColour; + _colour = colour; + _dyeColour = dyeColour; + _spawns = spawns; + _players = new HashMap<>(); + _places = new LinkedList<>(); + + Collections.shuffle(spawns); + } + + public String getName() + { + return _name; + } + + public ChatColor getChatColour() + { + return _chatColour; + } + + public Color getColour() + { + return _colour; + } + + public DyeColor getDyeColour() + { + return _dyeColour; + } + + public byte getWoolData() + { + return _dyeColour.getWoolData(); + } + + public Location getSpawn() + { + // If only 1 spawn, skip the effort and just return it + if (getSpawns().size() == 1) + { + return getSpawns().get(0); + } + + // Players are being teleported in and there are more players than spawns already in + // If this is the case just start placing players randomly otherwise they'll all end up + // at the same spawn. + if (!_game.isLive() && getAllPlayers().size() > getSpawns().size()) + { + _overflowIndex = (_overflowIndex + 1) % getSpawns().size(); + return getSpawns().get(_overflowIndex); + } + + // Try and spawn the player as far away as possible from other players + return UtilAlg.getLocationAwayFromPlayers(getSpawns(), _game.getAlivePlayers()); + } + + public List getSpawns() + { + return _spawns; + } + + public void setPlayerAlive(Player player, boolean alive) + { + _players.put(player, alive); + + if (alive) + { + _places.remove(player); + } + else + { + _places.addFirst(player); + } + + UtilServer.CallEvent(new PlayerStateChangeEvent(player, this, alive)); + } + + public void removePlayer(Player player) + { + _players.remove(player); + } + + public Collection getAllPlayers() + { + return _players.keySet(); + } + + public boolean hasPlayer(Player player) + { + return _players.containsKey(player); + } + + public List getAlivePlayers() + { + return _players.entrySet().stream() + .filter(Entry::getValue) + .map(Entry::getKey) + .collect(Collectors.toList()); + } + + public boolean isAlive(Player player) + { + return _players.getOrDefault(player, false); + } + + public void addPlacementTop(Player player) + { + _places.addFirst(player); + } + + public void addPlacementBottom(Player player) + { + _places.addLast(player); + } + + public List getPlaces(boolean includeAlive) + { + if (includeAlive) + { + LinkedList places = new LinkedList<>(_places); + getAlivePlayers().forEach(places::addFirst); + return places; + } + + return _places; + } + + public List getActualPlaces() + { + return _places; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeamComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeamComponent.java new file mode 100644 index 000000000..465d93a17 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/GameTeamComponent.java @@ -0,0 +1,216 @@ +package mineplex.game.nano.game.components.team; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerQuitEvent; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.recharge.Recharge; +import mineplex.game.nano.NanoPlayer; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.components.world.GameWorldComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerGameApplyEvent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; + +public class GameTeamComponent extends GameComponent implements TeamComponent +{ + + private static final String RESPAWN_RECHARGE_KEY = "Respawn"; + private final List _teams; + + private Function _selector; + private boolean _adjustSpawnYaw = true; + private long _respawnRechargeTime = TimeUnit.SECONDS.toMillis(2); + + public GameTeamComponent(Game game) + { + super(game); + + _teams = new ArrayList<>(); + _selector = player -> game.getTeams().stream() + .min(Comparator.comparingInt(o -> o.getAllPlayers().size())) + .orElse(null); + } + + public GameTeamComponent setSelector(Function selector) + { + _selector = selector; + return this; + } + + public GameTeamComponent setAdjustSpawnYaw(boolean adjustSpawnYaw) + { + _adjustSpawnYaw = adjustSpawnYaw; + return this; + } + + public GameTeamComponent setRespawnRechargeTime(long respawnRechargeTime) + { + _respawnRechargeTime = respawnRechargeTime; + return this; + } + + @Override + public void disable() + { + _teams.clear(); + } + + @EventHandler(priority = EventPriority.LOW) + public void assignTeams(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + for (Player player : UtilServer.getPlayersCollection()) + { + GameTeam team = getGame().getManager().isSpectator(player) ? null : _selector.apply(player); + + if (team == null) + { + getGame().addSpectator(player, true, false); + } + else + { + team.setPlayerAlive(player, true); + respawnPlayer(player, team); + } + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + GameTeam team = getTeam(player); + + if (team != null) + { + team.setPlayerAlive(player, false); + } + } + + @Override + public GameTeam addTeam(GameTeam gameTeam) + { + _teams.add(gameTeam); + getGame().getManager().log("Created team : " + gameTeam.getChatColour() + gameTeam.getName()); + return gameTeam; + } + + @Override + public List getTeams() + { + return _teams; + } + + @Override + public void joinTeam(Player player, GameTeam team) + { + GameTeam oldTeam = getTeam(player); + + if (oldTeam != null) + { + oldTeam.removePlayer(player); + } + + team.setPlayerAlive(player, true); + } + + @Override + public final GameTeam getTeam(Player player) + { + return _teams.stream() + .filter(gameTeam -> gameTeam.hasPlayer(player)) + .findFirst() + .orElse(null); + } + + @Override + public boolean isAlive(Player player) + { + return _teams.stream() + .anyMatch(gameTeam -> gameTeam.isAlive(player)); + } + + @Override + public void respawnPlayer(Player player, GameTeam team) + { + Location location = team.getSpawn(); + + if (location == null) + { + location = getGame().getSpectatorLocation(); + } + else if (_adjustSpawnYaw && location.getYaw() == 0) + { + Location lookAt = getGame().getMineplexWorld().getSpongeLocation("LOOK_AT"); + + if (lookAt == null) + { + lookAt = getGame().getSpectatorLocation(); + } + + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, lookAt))); + } + + PlayerGameApplyEvent applyEvent = new PlayerGameApplyEvent(player, team, location, true); + UtilServer.CallEvent(applyEvent); + + if (applyEvent.isClearPlayer()) + { + NanoPlayer.clear(getGame().getManager(), player); + NanoPlayer.setSpectating(player, false); + + GameWorldComponent worldComponent = getGame().getManager().getGameWorldManager().getHook(); + + if (worldComponent != null && (worldComponent.isBlockBreak() || worldComponent.isBlockPlace())) + { + player.setGameMode(GameMode.SURVIVAL); + } + } + + player.teleport(applyEvent.getRespawnLocation()); + Recharge.Instance.useForce(player, RESPAWN_RECHARGE_KEY, _respawnRechargeTime); + + UtilServer.CallEvent(new PlayerGameRespawnEvent(player, team)); + } + + @Override + public boolean hasRespawned(Player player) + { + return !Recharge.Instance.usable(player, RESPAWN_RECHARGE_KEY); + } + + @Override + public List getAllPlayers() + { + return getTeams().stream() + .flatMap(gameTeam -> gameTeam.getAllPlayers().stream()) + .collect(Collectors.toList()); + } + + @Override + public List getAlivePlayers() + { + return getTeams().stream() + .flatMap(gameTeam -> gameTeam.getAlivePlayers().stream()) + .collect(Collectors.toList()); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/TeamComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/TeamComponent.java new file mode 100644 index 000000000..cc618f4d2 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/team/TeamComponent.java @@ -0,0 +1,28 @@ +package mineplex.game.nano.game.components.team; + +import java.util.List; + +import org.bukkit.entity.Player; + +public interface TeamComponent +{ + + GameTeam addTeam(GameTeam gameTeam); + + List getTeams(); + + void joinTeam(Player player, GameTeam team); + + GameTeam getTeam(Player player); + + boolean isAlive(Player player); + + void respawnPlayer(Player player, GameTeam team); + + boolean hasRespawned(Player player); + + List getAllPlayers(); + + List getAlivePlayers(); + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWaterComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWaterComponent.java new file mode 100644 index 000000000..70469562c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWaterComponent.java @@ -0,0 +1,67 @@ +package mineplex.game.nano.game.components.world; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +public class GameWaterComponent extends GameComponent +{ + + private boolean _override; + + public GameWaterComponent(Game game) + { + super(game, GameState.Live); + } + + @Override + public void disable() + { + + } + + public GameWaterComponent override() + { + _override = true; + return this; + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.getState() != GameState.Live) + { + return; + } + + if (getGame().getMineplexWorld().getSpongeLocation("WATER_DAMAGE") != null) + { + _override = true; + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !_override) + { + return; + } + + for (Player player : getGame().getAlivePlayers()) + { + if (UtilEnt.isInWater(player)) + { + getGame().getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.DROWNING, 2, false, false, false, getGame().getGameType().getName(), "Water Damage"); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldComponent.java new file mode 100644 index 000000000..f4f800f95 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldComponent.java @@ -0,0 +1,108 @@ +package mineplex.game.nano.game.components.world; + +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.GameComponent; + +public class GameWorldComponent extends GameComponent +{ + + // Entities + private boolean _creatureAllow, _creatureAllowOverride; + + // Blocks + private boolean _blockBreak, _blockPlace, _blockInteract; + + // World + private boolean _allowWeather; + private boolean _worldBoundaryKill = true; + + public GameWorldComponent(Game game) + { + super(game); + + game.getManager().getGameWorldManager().setHook(this); + } + + @Override + public void disable() + { + + } + + public GameWorldComponent setCreatureAllow(boolean creatureAllow) + { + _creatureAllow = creatureAllow; + return this; + } + + public boolean isCreatureAllow() + { + return _creatureAllow; + } + + public GameWorldComponent setCreatureAllowOverride(boolean creatureAllowOverride) + { + _creatureAllowOverride = creatureAllowOverride; + return this; + } + + public boolean isCreatureAllowOverride() + { + return _creatureAllowOverride; + } + + public GameWorldComponent setBlockBreak(boolean blockBreak) + { + _blockBreak = blockBreak; + return this; + } + + public boolean isBlockBreak() + { + return _blockBreak; + } + + public GameWorldComponent setBlockPlace(boolean blockPlace) + { + _blockPlace = blockPlace; + return this; + } + + public boolean isBlockPlace() + { + return _blockPlace; + } + + public GameWorldComponent setAllowWeather(boolean allowWeather) + { + _allowWeather = allowWeather; + return this; + } + + public GameWorldComponent setBlockInteract(boolean blockInteract) + { + _blockInteract = blockInteract; + return this; + } + + public boolean isBlockInteract() + { + return _blockInteract; + } + + public boolean isAllowWeather() + { + return _allowWeather; + } + + public GameWorldComponent setWorldBoundaryKill(boolean worldBoundaryKill) + { + _worldBoundaryKill = worldBoundaryKill; + return this; + } + + public boolean isWorldBoundaryKill() + { + return _worldBoundaryKill; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldManager.java new file mode 100644 index 000000000..366bcae6d --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/components/world/GameWorldManager.java @@ -0,0 +1,277 @@ +package mineplex.game.nano.game.components.world; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerArmorStandManipulateEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.weather.WeatherChangeEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.StructureGrowEvent; +import org.bukkit.util.Vector; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.components.ComponentHook; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class GameWorldManager extends GameManager implements ComponentHook +{ + + private GameWorldComponent _hook; + + private GameWorldManager() + { + super("World Hook"); + } + + @Override + public void setHook(GameWorldComponent hook) + { + _hook = hook; + } + + @Override + public GameWorldComponent getHook() + { + return _hook; + } + + @EventHandler + public void gameDeath(GameStateChangeEvent event) + { + if (event.getState() == GameState.Dead) + { + setHook(null); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void creatureSpawn(CreatureSpawnEvent event) + { + if (_hook == null || !_hook.isCreatureAllow() && !_hook.isCreatureAllowOverride()) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void creatureSpawnChunk(CreatureSpawnEvent event) + { + event.getEntity().getLocation().getChunk(); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockBreak(BlockBreakEvent event) + { + if (_hook == null || !_hook.getGame().isLive() || !_hook.isBlockBreak() || UtilPlayer.isSpectator(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void blockPlace(BlockPlaceEvent event) + { + if (_hook == null || !_hook.getGame().isLive() || !_hook.isBlockPlace() || UtilPlayer.isSpectator(event.getPlayer())) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void weatherChange(WeatherChangeEvent event) + { + if (event.toWeatherState() && (_hook == null || !_hook.isAllowWeather())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void updateBoundary(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + MineplexWorld mineplexWorld; + Location fallbackLocation = null; + + // No hook, in Lobby + if (_hook == null) + { + mineplexWorld = _manager.getLobbyManager().getMineplexWorld(); + fallbackLocation = _manager.getLobbyManager().getSpawn(); + } + else + { + mineplexWorld = _hook.getGame().getMineplexWorld(); + + if (mineplexWorld != null) + { + fallbackLocation = _hook.getGame().getSpectatorLocation(); + } + } + + if (mineplexWorld == null || fallbackLocation == null) + { + return; + } + + Location min = mineplexWorld.getMin(), max = mineplexWorld.getMax(); + + for (Player player : UtilServer.getPlayersCollection()) + { + Location location = player.getLocation(); + + // Inside map + if (UtilAlg.inBoundingBox(location, min, max)) + { + continue; + } + + // No hook or spectator + if (_hook == null || UtilPlayer.isSpectator(player)) + { + player.teleport(fallbackLocation); + } + else + { + double damage = 4; + + // Instant kill or in void + if (_hook.isWorldBoundaryKill() || location.getY() < min.getY()) + { + damage = 500; + } + else + { + Vector velocity = UtilAlg.getTrajectory2d(location, fallbackLocation); + velocity.setY(1); + + UtilAction.velocity(player, velocity); + player.playSound(location, Sound.NOTE_BASS, 1, 0.5F); + player.sendMessage(F.main(_manager.getName(), C.cRed + "RETURN TO THE PLAYABLE AREA!")); + } + + _manager.getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, damage, false, true, true, _hook.getGame().getGameType().getName(), "World Border"); + } + } + + } + + @EventHandler + public void chunkUnload(ChunkUnloadEvent event) + { + if (_hook != null) + { + MineplexWorld mineplexWorld = _hook.getGame().getMineplexWorld(); + + if (mineplexWorld != null && mineplexWorld.getWorld().equals(event.getWorld())) + { + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void blockInteract(PlayerInteractEvent event) + { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK || (_hook != null && _hook.isBlockInteract())) + { + return; + } + + Block block = event.getClickedBlock(); + Material material = block.getType(); + + if (material != Material.WOODEN_DOOR && material != Material.IRON_DOOR_BLOCK && UtilBlock.usable(block)) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void blockGrow(BlockGrowEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockFromTo(BlockFromToEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockSpread(BlockSpreadEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockBurn(BlockBurnEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockIgnite(BlockIgniteEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void leavesDecay(LeavesDecayEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void structureGrow(StructureGrowEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockForm(BlockFormEvent event) + { + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.LOW) + public void armourStand(PlayerArmorStandManipulateEvent event) + { + event.setCancelled(true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameEvent.java new file mode 100644 index 000000000..05524828d --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameEvent.java @@ -0,0 +1,21 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.event.Event; + +import mineplex.game.nano.game.Game; + +public abstract class GameEvent extends Event +{ + + private final Game _game; + + public GameEvent(Game game) + { + _game = game; + } + + public Game getGame() + { + return _game; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameStateChangeEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameStateChangeEvent.java new file mode 100644 index 000000000..75dae3783 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameStateChangeEvent.java @@ -0,0 +1,37 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.event.HandlerList; + +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; + +public class GameStateChangeEvent extends GameEvent +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + private final GameState _state; + + public GameStateChangeEvent(Game game, GameState state) + { + super(game); + + _state = state; + } + + public GameState getState() + { + return _state; + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameTimeoutEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameTimeoutEvent.java new file mode 100644 index 000000000..de6d7f9bd --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/GameTimeoutEvent.java @@ -0,0 +1,27 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.event.HandlerList; + +import mineplex.game.nano.game.Game; + +public class GameTimeoutEvent extends GameEvent +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + public GameTimeoutEvent(Game game) + { + super(game); + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerDeathOutEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerDeathOutEvent.java new file mode 100644 index 000000000..cc3106483 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerDeathOutEvent.java @@ -0,0 +1,53 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class PlayerDeathOutEvent extends PlayerEvent implements Cancellable +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + private boolean _shouldRespawn = true; + private boolean _cancelled; + + public PlayerDeathOutEvent(Player who) + { + super(who); + } + + public void setShouldRespawn(boolean shouldRespawn) + { + _shouldRespawn = shouldRespawn; + } + + public boolean shouldRespawn() + { + return _shouldRespawn; + } + + @Override + public void setCancelled(boolean cancelled) + { + _cancelled = cancelled; + } + + @Override + public boolean isCancelled() + { + return _cancelled; + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameApplyEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameApplyEvent.java new file mode 100644 index 000000000..5d9f2f26b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameApplyEvent.java @@ -0,0 +1,63 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +import mineplex.game.nano.game.components.team.GameTeam; + +public class PlayerGameApplyEvent extends PlayerEvent +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + private final GameTeam _team; + private Location _respawnLocation; + private boolean _clearPlayer; + + public PlayerGameApplyEvent(Player who, GameTeam team, Location respawnLocation, boolean clearPlayer) + { + super(who); + + _team = team; + _respawnLocation = respawnLocation; + _clearPlayer = clearPlayer; + } + + public GameTeam getTeam() + { + return _team; + } + + public void setRespawnLocation(Location respawnLocation) + { + _respawnLocation = respawnLocation; + } + + public Location getRespawnLocation() + { + return _respawnLocation.clone(); + } + + public void setClearPlayer(boolean clearPlayer) + { + _clearPlayer = clearPlayer; + } + + public boolean isClearPlayer() + { + return _clearPlayer; + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameRespawnEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameRespawnEvent.java new file mode 100644 index 000000000..016785a0c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerGameRespawnEvent.java @@ -0,0 +1,38 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +import mineplex.game.nano.game.components.team.GameTeam; + +public class PlayerGameRespawnEvent extends PlayerEvent +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + private final GameTeam _team; + + public PlayerGameRespawnEvent(Player who, GameTeam team) + { + super(who); + + _team = team; + } + + public GameTeam getTeam() + { + return _team; + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerStateChangeEvent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerStateChangeEvent.java new file mode 100644 index 000000000..e7e3c0102 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/event/PlayerStateChangeEvent.java @@ -0,0 +1,45 @@ +package mineplex.game.nano.game.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +import mineplex.game.nano.game.components.team.GameTeam; + +public class PlayerStateChangeEvent extends PlayerEvent +{ + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + public static HandlerList getHandlerList() + { + return HANDLER_LIST; + } + + private final GameTeam _team; + private final boolean _alive; + + public PlayerStateChangeEvent(Player who, GameTeam team, boolean alive) + { + super(who); + + _team = team; + _alive = alive; + } + + public GameTeam getTeam() + { + return _team; + } + + public boolean isAlive() + { + return _alive; + } + + @Override + public HandlerList getHandlers() + { + return HANDLER_LIST; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/bawkbawk/BawkBawk.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/bawkbawk/BawkBawk.java new file mode 100644 index 000000000..e8bf4f073 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/bawkbawk/BawkBawk.java @@ -0,0 +1,239 @@ +package mineplex.game.nano.game.games.bawkbawk; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class BawkBawk extends SoloGame +{ + + private static final int PLATFORM_HEIGHT = 5; + + private List _possiblePlatforms; + private Location _lastPlatform; + + private int _rounds; + private long _roundTime = TimeUnit.SECONDS.toMillis(9), _roundEndTime = TimeUnit.SECONDS.toMillis(3); + private long _lastRoundStart, _lastRoundEnd; + private boolean _roundOver; + private int _platfromSize = 2; + + public BawkBawk(NanoManager manager) + { + super(manager, GameType.BAWK_BAWK, new String[] + { + C.cYellow + "Bawk Bawk" + C.Reset + " is angry!", + "Get to the " + C.cRed + "Platform" + C.Reset + " before the time runs out!", + C.cRed + "PvP" + C.Reset + " is enabled at " + C.cGreen + "Round 3" + C.Reset + "!", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent + .setPvp(false) + .setFall(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(150)); + } + + @Override + protected void parseData() + { + _possiblePlatforms = _mineplexWorld.getIronLocations("RED"); + _roundOver = true; + } + + @Override + public void disable() + { + + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false, false)); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + Player[] players = getAlivePlayers().toArray(new Player[0]); + + if (_roundOver) + { + // Round over + if (UtilTime.elapsed(_lastRoundEnd, _roundEndTime)) + { + generatePlatform(); + + _rounds++; + _lastRoundStart = System.currentTimeMillis(); + _roundOver = false; + + if (_roundTime > 5000) + { + _roundTime -= 250; + } + + if (_rounds % 6 == 0 && _platfromSize > 0) + { + _platfromSize--; + } + + if (_rounds == 3) + { + _damageComponent.setPvp(true); + announce(F.main(getManager().getName(), F.color("PvP", C.cRedB) + " is now " + F.greenElem("Enabled") + "!")); + UtilTextMiddle.display(null, C.cRed + "PvP is enabled!", 10, 20, 10, players); + } + else + { + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.CHICKEN_IDLE, 1, 1); + } + + UtilTextMiddle.display(null, C.cGreen + "Get to the Platform", 10, 20, 10, players); + } + } + } + else + { + long diff = System.currentTimeMillis() - _lastRoundStart; + + if (diff > _roundTime) + { + setWalls(_lastPlatform, false); + + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 0.2F); + } + + UtilTextBottom.display(C.cRedB + "BAWK BAWK", players); + + getManager().runSyncLater(() -> + { + double size = _platfromSize + 0.6; + Location a = _lastPlatform.clone().add(size, PLATFORM_HEIGHT, size), b = _lastPlatform.clone().subtract(size, 0, size); + + for (Player player : players) + { + Location location = player.getLocation(); + + if (!UtilAlg.inBoundingBox(location, a, b)) + { + location.getWorld().strikeLightningEffect(location); + _manager.getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 500, false, true, true, getGameType().getName(), "Lightning"); + } + } + }, 40); + + _lastRoundEnd = System.currentTimeMillis(); + _roundOver = true; + } + else + { + diff = _roundTime - diff; + + UtilTextBottom.displayProgress("Round " + _rounds, (double) diff / _roundTime, UtilTime.MakeStr(Math.max(0, diff)), players); + } + } + } + + private void generatePlatform() + { + while (true) + { + Location location = UtilAlg.Random(_possiblePlatforms); + + if (location == null) + { + return; + } + + if (_lastPlatform != null) + { + if (UtilMath.offsetSquared(_lastPlatform, location) < 25) + { + continue; + } + + setPlatform(_lastPlatform, true); + setWalls(_lastPlatform, true); + } + + setPlatform(location, false); + _lastPlatform = location; + + break; + } + } + + private void setPlatform(Location center, boolean air) + { + for (Block block : UtilBlock.getInBoundingBox(center.clone().add(_platfromSize, 0, _platfromSize), center.clone().subtract(_platfromSize, 0, _platfromSize), false)) + { + Location location = block.getLocation(); + + MapUtil.QuickChangeBlockAt(location, air ? Material.AIR : Material.STAINED_CLAY, (byte) 14); + MapUtil.QuickChangeBlockAt(location.add(0, 5, 0), air ? Material.AIR : Material.WOOD_STEP); + } + } + + private void setWalls(Location center, boolean air) + { + int size = _platfromSize + 1; + + for (Block block : UtilBlock.getInBoundingBox(center.clone().add(size, PLATFORM_HEIGHT, size), center.clone().subtract(size, 0, size), false, false, true, false)) + { + MapUtil.QuickChangeBlockAt(block.getLocation(), air ? Material.AIR : Material.STAINED_GLASS, (byte) 14); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + if (event.GetCause() == DamageCause.CUSTOM) + { + return; + } + + event.AddMod(getGameType().getName(), -event.GetDamage() + 0.1); + event.AddKnockback(getGameType().getName(), 3); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/chickenshoot/ChickenShoot.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/chickenshoot/ChickenShoot.java new file mode 100644 index 000000000..83379c950 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/chickenshoot/ChickenShoot.java @@ -0,0 +1,233 @@ +package mineplex.game.nano.game.games.chickenshoot; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Chicken; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.components.player.GiveItemComponent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class ChickenShoot extends ScoredSoloGame +{ + + private static final int MAX_MOBS = 30; + + private final Map _mobs; + + private List _mobSpawns; + + public ChickenShoot(NanoManager manager) + { + super(manager, GameType.CHICKEN_SHOOT, new String[] + { + "Look up! " + C.cYellow + "Chickens" + C.Reset + " are falling from the sky!", + C.cRed + "Shoot Them" + C.Reset + " with your bow for points!", + C.cYellow + "Most points" + C.Reset + " wins!" + }); + + _mobs = new HashMap<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent + .setPvp(false) + .setFall(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(75)); + + new GiveItemComponent(this) + .setItems(new ItemStack[] + { + new ItemBuilder(Material.BOW) + .addEnchantment(Enchantment.ARROW_INFINITE, 1) + .setUnbreakable(true) + .build(), + new ItemStack(Material.ARROW) + }) + .setArmour(new ItemStack[] + { + null, + null, + null, + new ItemBuilder(Material.SKULL_ITEM, (byte) 3) + .setPlayerHead("MHF_Chicken") + .setTitle(C.cYellow + "Chicken Head") + .build() + }); + } + + @Override + protected void parseData() + { + _mobSpawns = _mineplexWorld.getIronLocations("LIME"); + } + + @EventHandler + public void updateMobs(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive()) + { + return; + } + + _mobs.keySet().removeIf(entity -> + { + if (!entity.isValid() || UtilEnt.isGrounded(entity)) + { + kill(entity); + return true; + } + + return false; + }); + + _worldComponent.setCreatureAllowOverride(true); + + while (_mobs.size() < MAX_MOBS) + { + Location location = UtilAlg.Random(_mobSpawns); + + if (location == null) + { + break; + } + + location = location.clone().add(0, 13, 0); + location.setYaw(UtilMath.r(360)); + + _worldComponent.setCreatureAllowOverride(true); + + Chicken chicken = location.getWorld().spawn(location, Chicken.class); + int points; + String colour = ""; + + if (Math.random() < 0.1) + { + points = 5; + colour = C.cPurple; + + Zombie zombie = location.getWorld().spawn(location, Zombie.class); + + zombie.setBaby(true); + zombie.setCustomName(colour + C.Bold + points); + zombie.setCustomNameVisible(true); + zombie.setHealth(1); + zombie.setHealth(1); + + chicken.setPassenger(zombie); + + _mobs.put(zombie, points); + } + else + { + points = UtilMath.rRange(1, 3); + + switch (points) + { + case 1: + colour = C.cAqua; + break; + case 2: + colour = C.cGreen; + break; + case 3: + colour = C.cYellow; + break; + } + + chicken.setCustomName(colour + C.Bold + points); + chicken.setCustomNameVisible(true); + } + + chicken.setHealth(1); + chicken.setMaxHealth(1); + + _mobs.put(chicken, points); + } + + _worldComponent.setCreatureAllowOverride(true); + } + + @EventHandler(ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + if (event.GetProjectile() == null) + { + event.SetCancelled("No Projectile"); + } + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + LivingEntity entity = event.getEntity(); + Integer points = _mobs.remove(entity); + + if (points != null) + { + event.getDrops().clear(); + event.setDroppedExp(0); + + kill(entity); + + Player killer = entity.getKiller(); + + if (killer == null) + { + return; + } + + incrementScore(killer, points); + UtilTextMiddle.display(null, C.cGreen + "+" + points, 5, 20, 5, killer); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void projectileHit(ProjectileHitEvent event) + { + event.getEntity().remove(); + } + + private void kill(LivingEntity entity) + { + if (entity.getPassenger() != null) + { + entity.getPassenger().remove(); + } + + if (entity.getVehicle() != null) + { + entity.getVehicle().remove(); + } + + if (!entity.isDead()) + { + entity.remove(); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/colourchange/ColourChange.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/colourchange/ColourChange.java new file mode 100644 index 000000000..6f3979c6e --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/colourchange/ColourChange.java @@ -0,0 +1,272 @@ +package mineplex.game.nano.game.games.colourchange; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilColor; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; + +public class ColourChange extends SoloGame +{ + + private final Map _tileMap; + private final DyeColor[] _colourPool = new DyeColor[] + { + DyeColor.RED, + DyeColor.YELLOW, + DyeColor.GREEN, + DyeColor.BLUE, + DyeColor.ORANGE, + DyeColor.LIME, + DyeColor.LIGHT_BLUE, + DyeColor.GRAY, + DyeColor.WHITE, + DyeColor.PINK, + DyeColor.PURPLE, + }; + private final List _usableColours; + private final BlockFace[] _faces = new BlockFace[] + { + BlockFace.SELF, + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST, + BlockFace.NORTH_WEST, + BlockFace.NORTH_EAST, + BlockFace.SOUTH_WEST, + BlockFace.SOUTH_EAST + }; + + private int _minY; + private int _rounds; + private long _roundTime = TimeUnit.SECONDS.toMillis(5), _roundEndTime = TimeUnit.SECONDS.toMillis(3); + private long _lastRoundStart, _lastRoundEnd; + private DyeColor _target; + private ChatColor _targetChat; + private String _targetName; + private boolean _roundOver; + + public ColourChange(NanoManager manager) + { + super(manager, GameType.COLOUR_CHANGE, new String[] + { + C.cYellow + "Stand" + C.Reset + " on the color shown.", + "All others " + C.cRed + "Disappear" + C.Reset + " after a few seconds.", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + + _usableColours = new ArrayList<>(_colourPool.length); + _tileMap = new HashMap<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setPvp(false); + + _endComponent.setTimeout(TimeUnit.MINUTES.toMillis(2)); + } + + @Override + protected void parseData() + { + for (int i = 0; i < 4; i++) + { + _usableColours.add(_colourPool[i]); + } + + _roundOver = true; + + List tiles = _mineplexWorld.getIronLocations("RED"); + _minY = tiles.get(0).getBlockY() + 1; + + tiles.forEach(location -> + { + _tileMap.put(location, null); + setTile(location, UtilMath.randomElement(_colourPool)); + }); + } + + @Override + public void disable() + { + _usableColours.clear(); + _tileMap.clear(); + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + event.getPlayersToInform().clear(); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + Player[] players = getAlivePlayers().toArray(new Player[0]); + + if (_roundOver) + { + // Round over + if (UtilTime.elapsed(_lastRoundEnd, _roundEndTime)) + { + generateFloor(); + _target = randomColour(); + _targetChat = UtilColor.woolDataToChatColor(_target.getWoolData()); + _targetName = _target.toString().replace("_", " "); + + ItemStack itemStack = new ItemBuilder(Material.WOOL, _target.getWoolData()) + .setTitle(_targetChat + C.Bold + _targetName) + .build(); + + for (Player player : players) + { + PlayerInventory inventory = player.getInventory(); + + for (int i = 0; i < 9; i++) + { + inventory.setItem(i, itemStack); + } + } + + _rounds++; + _lastRoundStart = System.currentTimeMillis(); + _roundOver = false; + + if (_roundTime > 1000) + { + _roundTime -= 200; + } + + if (_roundEndTime > 1500) + { + _roundEndTime -= 100; + } + + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1); + } + + UtilTextMiddle.display(null, _targetChat + C.Bold + _targetName, 10, 20, 10, players); + + if (_rounds % 2 == 0 && _usableColours.size() < _colourPool.length) + { + _usableColours.add(_colourPool[_usableColours.size()]); + } + } + else + { + for (Player player : players) + { + if (player.getLocation().getBlockY() < _minY) + { + UtilFirework.launchFirework(player.getLocation(), FireworkEffect.builder() + .with(UtilMath.randomElement(Type.values())) + .withColor(_target.getColor()) + .build(), null, 1); + _manager.getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 500, false, true, true, getGameType().getName(), null); + } + } + } + } + else + { + long diff = System.currentTimeMillis() - _lastRoundStart; + + if (diff > _roundTime) + { + _tileMap.forEach((location, colour) -> + { + if (!_target.equals(colour)) + { + setTile(location, null); + } + }); + + for (Player player : players) + { + player.playSound(player.getLocation(), Sound.NOTE_SNARE_DRUM, 1, 0.2F); + } + UtilTextBottom.display(_targetChat + C.Bold + "SWAP!", players); + + _lastRoundEnd = System.currentTimeMillis(); + _roundOver = true; + } + else + { + diff = _roundTime - diff; + + UtilTextBottom.displayProgress(_targetChat + _targetName, (double) diff / _roundTime, UtilTime.MakeStr(Math.max(0, diff)), players); + } + } + } + + private void generateFloor() + { + _tileMap.entrySet().forEach(entry -> + { + DyeColor colour = randomColour(); + + setTile(entry.getKey(), colour); + entry.setValue(colour); + }); + } + + private void setTile(Location tile, DyeColor colour) + { + for (BlockFace face : _faces) + { + Location location = tile.clone().add(face.getModX(), 0, face.getModZ()); + + if (colour == null) + { + MapUtil.QuickChangeBlockAt(location, Material.AIR); + } + else + { + MapUtil.QuickChangeBlockAt(location, Material.WOOL, colour.getWoolData()); + } + } + } + + private DyeColor randomColour() + { + return UtilAlg.Random(_usableColours); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/copycat/CopyCat.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/copycat/CopyCat.java new file mode 100644 index 000000000..533fae414 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/copycat/CopyCat.java @@ -0,0 +1,246 @@ +package mineplex.game.nano.game.games.copycat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.games.copycat.CopyCat.SealBreakerRoom; +import mineplex.game.nano.game.roomed.Room; +import mineplex.game.nano.game.roomed.RoomedSoloGame; + +public class CopyCat extends RoomedSoloGame +{ + + private static final int X_SIZE = 3, Y_SIZE = 3; + + private final Set _blocks; + private final Material[] _material = + { + Material.DIRT, + Material.COBBLESTONE, + Material.WOOL, + Material.EMERALD_BLOCK + }; + + public CopyCat(NanoManager manager) + { + super(manager, GameType.COPY_CAT, new String[] + { + C.cYellow + "Copy" + C.Reset + " the pattern on the " + C.cGreen + "Left" + C.Reset + ".", + "And replicate it on the " + C.cGreen + "Right" + C.Reset + "!", + "Use the " + C.cAqua + "Markings" + C.Reset + " on the wall to help.", + C.cYellow + "Most patterns copied" + C.Reset + " wins!" + }); + + _blocks = new HashSet<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent + .setPvp(false) + .setFall(false); + + _worldComponent.setBlockPlace(true); + _worldComponent.setBlockBreak(true); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(90)); + } + + @Override + public void disable() + { + super.disable(); + + _blocks.clear(); + } + + @Override + protected SealBreakerRoom addPlayer(Player player, Location location, Map localPoints) + { + return new SealBreakerRoom(player, location, localPoints); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + player.setAllowFlight(true); + player.setFlying(true); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive()) + { + return; + } + + _rooms.forEach((player, room) -> + { + if (!player.isFlying()) + { + player.setFlying(true); + } + + if (room.next()) + { + UtilTextMiddle.display(C.cYellowB + "Level " + room.Level, C.cRed + room.Blocks + " Blocks", 0, 40, 0, player); + player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, 1); + + player.getInventory().clear(); + + room.Colours.forEach((material, amount) -> player.getInventory().addItem(new ItemStack(material, amount))); + } + }); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void blockPlace(BlockPlaceEvent event) + { + Player player = event.getPlayer(); + Block block = event.getBlock(); + SealBreakerRoom room = _rooms.get(player); + + if (room != null && room.isInPasteArea(block)) + { + _blocks.add(block); + } + else + { + player.sendMessage(F.main(getManager().getName(), "You can only place blocks in the designated area.")); + event.setCancelled(true); + } + } + + @EventHandler + public void blockDamage(BlockDamageEvent event) + { + if (!isLive()) + { + return; + } + + Block block = event.getBlock(); + + if (_blocks.remove(block)) + { + Player player = event.getPlayer(); + + player.playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); + player.getInventory().addItem(new ItemStack(block.getType())); + block.setType(Material.AIR); + } + else + { + event.setCancelled(true); + } + } + + class SealBreakerRoom extends Room + { + + int Level; + int Blocks = 3; + Map Colours; + Block CopyCenter; + Block PasteCenter; + + SealBreakerRoom(Player player, Location center, Map dataPoints) + { + super(player, center, dataPoints); + + Colours = new HashMap<>(); + CopyCenter = dataPoints.get("RED").getBlock(); + PasteCenter = dataPoints.get("ORANGE").getBlock(); + } + + boolean next() + { + for (int x = -X_SIZE; x <= X_SIZE; x++) + { + for (int y = -Y_SIZE; y <= Y_SIZE; y++) + { + Block copy = CopyCenter.getRelative(x, y, 0); + Block paste = PasteCenter.getRelative(x, y, 0); + + if (copy.getType() != paste.getType()) + { + return false; + } + } + } + + Level++; + Blocks++; + incrementScore(getPlayer(), 1); + + List blocks = new ArrayList<>(); + + for (int x = -X_SIZE; x <= X_SIZE; x++) + { + for (int y = -Y_SIZE; y <= Y_SIZE; y++) + { + Block block = CopyCenter.getRelative(x, y, 0); + block.setType(Material.AIR); + blocks.add(block); + + PasteCenter.getRelative(x, y, 0).setType(Material.AIR); + } + } + + Colours.clear(); + + for (int i = 0; i < Blocks; i++) + { + Block random = UtilAlg.Random(blocks); + + if (random == null) + { + return false; + } + + blocks.remove(random); + + Material material = UtilMath.randomElement(_material); + + random.setType(material); + Colours.put(material, Colours.getOrDefault(material, 0) + 1); + } + + return true; + } + + boolean isInPasteArea(Block block) + { + return block.getZ() == PasteCenter.getZ() && block.getX() >= PasteCenter.getX() - X_SIZE && block.getX() <= PasteCenter.getX() + X_SIZE; + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/deathtag/DeathTag.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/deathtag/DeathTag.java new file mode 100644 index 000000000..8422b6c89 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/deathtag/DeathTag.java @@ -0,0 +1,289 @@ +package mineplex.game.nano.game.games.deathtag; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.disguise.disguises.DisguiseZombie; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GamePlacements; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.components.player.GiveItemComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerGameApplyEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class DeathTag extends SoloGame +{ + + private final GiveItemComponent _itemComponent; + + private GameTeam _runners, _chasers; + + public DeathTag(NanoManager manager) + { + super(manager, GameType.DEATH_TAG, new String[] + { + C.cGreen + "Run" + C.Reset + " from the " + C.cRed + "Undead!", + "If you die, you become " + C.cRed + "Undead!", + C.cYellow + "Last Human" + C.Reset + " alive wins!" + }); + + _spectatorComponent.setDeathOut(false); + + _teamComponent.setSelector(player -> _runners); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setTeamSelf(false); + + _playerComponent.setRegainHealth(false); + + _compassComponent.setGiveToAlive(true); + + _itemComponent = new GiveItemComponent(this) + .setItems(new ItemStack[] + { + new ItemBuilder(Material.IRON_AXE) + .setUnbreakable(true) + .build() + }); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + for (GameTeam team : getTeams()) + { + scoreboard.write(team.getChatColour() + C.Bold + team.getName()); + scoreboard.write(team.getAlivePlayers().size() + " Alive"); + + scoreboard.writeNewLine(); + } + + scoreboard.draw(); + }); + } + + @Override + protected void createTeams() + { + _runners = addTeam(new GameTeam(this, "Humans", ChatColor.GREEN, Color.LIME, DyeColor.GREEN, getPlayerTeamSpawns())); + _chasers = addTeam(new GameTeam(this, "Undead", ChatColor.RED, Color.RED, DyeColor.RED, getPlayerTeamSpawns())); + } + + @Override + protected void parseData() + { + + } + + @Override + public boolean endGame() + { + return super.endGame() || _runners.getAlivePlayers().size() <= 1; + } + + @Override + public void disable() + { + + } + + @Override + protected GamePlacements createPlacements() + { + return GamePlacements.fromTeamPlacements(_runners.getPlaces(true)); + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.getState() != GameState.Live) + { + return; + } + + _itemComponent.setItems(new ItemStack[] + { + new ItemBuilder(Material.IRON_SWORD) + .setUnbreakable(true) + .build() + }); + } + + @EventHandler + public void playerApply(PlayerGameApplyEvent event) + { + Player player = event.getPlayer(); + + if (isLive()) + { + if (!event.getTeam().equals(_chasers)) + { + setChaser(player, false); + event.setRespawnLocation(player.getLocation()); + } + else + { + event.setClearPlayer(false); + } + } + else + { + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 0, false, false)); + } + } + + @EventHandler + public void updateChasers(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive()) + { + return; + } + + int req = 1 + (int) ((System.currentTimeMillis() - getStateTime()) / 45000); + + while (_chasers.getAlivePlayers().size() < req) + { + Player player = UtilAlg.Random(_runners.getAlivePlayers()); + + if (player == null) + { + return; + } + + setChaser(player, true); + } + + if (_mineplexWorld.getWorld().getEntitiesByClass(Zombie.class).size() < 100) + { + Location location = UtilAlg.Random(getPlayerTeamSpawns()); + + if (location != null) + { + _worldComponent.setCreatureAllowOverride(true); + + Zombie zombie = location.getWorld().spawn(location, Zombie.class); + zombie.setTarget(UtilAlg.Random(_runners.getAlivePlayers())); + zombie.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 0, false, false)); + + _worldComponent.setCreatureAllowOverride(false); + } + } + } + + private void setChaser(Player player, boolean forced) + { + _runners.setPlayerAlive(player, false); + _teamComponent.joinTeam(player, _chasers); + + DisguiseZombie disguise = new DisguiseZombie(player); + + disguise.setName(_chasers.getChatColour() + player.getName()); + disguise.setCustomNameVisible(true); + + if (forced) + { + announce(F.main(getManager().getName(), F.elem(_runners.getChatColour() + player.getName()) + " has become an " + F.elem(_chasers.getChatColour() + "Alpha Zombie") + ".")); + player.getWorld().strikeLightningEffect(player.getLocation()); + player.getInventory().setArmorContents(new ItemStack[] + { + null, + null, + null, + new ItemBuilder(Material.SKULL_ITEM, (byte) 1) + .build() + }); + } + else + { + UtilPlayer.clearInventory(player); + } + + UtilTextMiddle.display(C.cRedB + "Zombie", "You are now a zombie!", 0, 60, 10, player); + _manager.getDisguiseManager().disguise(disguise); + + player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, Integer.MAX_VALUE, 4, false, false)); + player.removePotionEffect(PotionEffectType.SPEED); + + for (LivingEntity entity : player.getWorld().getLivingEntities()) + { + if (entity instanceof Creature) + { + Creature creature = (Creature) entity; + + if (player.equals(creature.getTarget())) + { + creature.setTarget(null); + } + } + } + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + event.setDroppedExp(0); + event.getDrops().clear(); + } + + @EventHandler + public void entityTarget(EntityTargetEvent event) + { + if (event.getEntity() instanceof Zombie && event.getTarget() instanceof Player && _chasers.hasPlayer((Player) event.getTarget())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void entityCombust(EntityCombustEvent event) + { + if (event.getEntity() instanceof Zombie) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void chaserDamage(CustomDamageEvent event) + { + if (_chasers.hasPlayer(event.GetDamagerPlayer(false))) + { + if (event.GetDamageeEntity() instanceof Zombie) + { + event.SetCancelled("Zombie vs Zombie"); + } + else + { + event.AddMod("Chaser", 2); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/findores/FindOres.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/findores/FindOres.java new file mode 100644 index 000000000..1d845c9b7 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/findores/FindOres.java @@ -0,0 +1,209 @@ +package mineplex.game.nano.game.games.findores; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.components.player.GiveItemComponent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; + +public class FindOres extends ScoredSoloGame +{ + + private enum OreType + { + COAL(Material.COAL_ORE, Material.COAL, 1, 600), + IRON(Material.IRON_ORE, Material.IRON_INGOT, 1, 600), + GOLD(Material.GOLD_ORE, Material.GOLD_INGOT, 2, 300), + DIAMOND(Material.DIAMOND_ORE, Material.DIAMOND, 3, 200), + EMERALD(Material.EMERALD_ORE, Material.EMERALD, 5, 100); + + final Material BlockType; + final Material DropType; + final int Points; + final int MaxVeins; + + OreType(Material blockType, Material dropType, int points, int maxVeins) + { + BlockType = blockType; + DropType = dropType; + Points = points; + MaxVeins = maxVeins; + } + } + + private final BlockFace[] _faces = + { + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST, + BlockFace.UP, + BlockFace.DOWN + }; + + private Location _cornerA, _cornerB; + + public FindOres(NanoManager manager) + { + super(manager, GameType.FIND_ORES, new String[] + { + C.cYellow + "Mine" + C.Reset + " ores to earn points.", + C.cAqua + "Diamonds" + C.Reset + " and " + C.cGreen + "Emeralds" + C.Reset + " give more points!", + C.cYellow + "Most points" + C.Reset + " wins." + }); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent + .setPvp(false) + .setFall(false); + + _worldComponent.setBlockBreak(true); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(100)); + + new GiveItemComponent(this) + .setItems(new ItemStack[] + { + new ItemBuilder(Material.DIAMOND_PICKAXE) + .setTitle(C.cAquaB + "Super Pick 5000") + .setGlow(true) + .setUnbreakable(true) + .build() + }); + } + + @Override + protected void parseData() + { + List corners = _mineplexWorld.getIronLocations("YELLOW"); + + _cornerA = corners.get(0); + _cornerB = corners.get(1); + + corners.forEach(location -> + { + Block block = location.getBlock(); + Block oneUp = block.getRelative(BlockFace.UP); + Block twoUp = location.getBlock().getRelative(0, 2, 0); + + block.setType(Material.BEDROCK); + oneUp.setType(twoUp.getType()); + oneUp.setData(twoUp.getData()); + }); + + List blocks = UtilBlock.getInBoundingBox(_cornerA, _cornerB); + + for (OreType oreType : OreType.values()) + { + for (int i = 0; i < oreType.MaxVeins; i++) + { + Block block = UtilAlg.Random(blocks); + + if (block == null) + { + break; + } + + blocks.remove(block); + + int max = UtilMath.rRange(3, 7); + + for (int j = 0; j < max; j++) + { + block = block.getRelative(UtilMath.randomElement(_faces)); + + if (!isInMap(block)) + { + break; + } + + MapUtil.QuickChangeBlockAt(block.getLocation(), oreType.BlockType); + } + } + } + } + + @EventHandler + public void playerRespawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + player.addPotionEffect(new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, false, false)); + } + + @EventHandler(priority = EventPriority.HIGH) + public void blockBreak(BlockDamageEvent event) + { + if (!isLive()) + { + return; + } + + Player player = event.getPlayer(); + + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null || itemStack.getType() != Material.DIAMOND_PICKAXE) + { + player.sendMessage(F.main(getManager().getName(), "Use your pickaxe to mine blocks!")); + event.setCancelled(true); + return; + } + + Block block = event.getBlock(); + + if (!isInMap(block)) + { + player.sendMessage(F.main(getManager().getName(), "You cannot break this block.")); + event.setCancelled(true); + return; + } + + for (OreType oreType : OreType.values()) + { + if (block.getType() != oreType.BlockType) + { + continue; + } + + incrementScore(player, oreType.Points); + player.getInventory().addItem(new ItemStack(oreType.DropType)); + UtilTextBottom.display(C.cYellow + "+" + oreType.Points + C.cGreen + " Point" + (oreType.Points == 1 ? "" : "s"), player); + break; + } + + event.setCancelled(true); + player.playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); + block.setType(Material.AIR); + } + + private boolean isInMap(Block block) + { + return UtilAlg.inBoundingBox(block.getLocation().add(0.5, -0.5, 0.5), _cornerA, _cornerB); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/jumprope/JumpRope.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/jumprope/JumpRope.java new file mode 100644 index 000000000..01300eb16 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/jumprope/JumpRope.java @@ -0,0 +1,165 @@ +package mineplex.game.nano.game.games.jumprope; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scoreboard.NameTagVisibility; +import org.bukkit.util.Vector; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class JumpRope extends SoloGame +{ + + private double _minY, _maxHeight; + private double _zDiff; + private double _theta, _thetaDelta = Math.PI / 40; + private Location _mid; + + public JumpRope(NanoManager manager) + { + super(manager, GameType.JUMP_ROPE, new String[] + { + C.cGreen + "Jump" + C.Reset + " over the particle rope!", + C.cRed + "Don't" + C.Reset + " get hit.", + "This game requires " + C.cPurple + "Particles" + C.Reset + " to be enabled!", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + + _prepareComponent.setPrepareFreeze(false); + + _playerComponent.setHideParticles(true); + + _damageComponent + .setPvp(false) + .setFall(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(100)); + + _scoreboardComponent.setSetupSettingsConsumer((player, team, scoreboardTeam) -> scoreboardTeam.setNameTagVisibility(NameTagVisibility.NEVER)); + } + + @Override + protected void parseData() + { + List ropePoints = _mineplexWorld.getIronLocations("RED"); + + Location a = ropePoints.get(0); + Location b = ropePoints.get(1); + + _zDiff = Math.abs(a.getZ() - b.getZ()) / 2; + + _minY = _playersTeam.getSpawn().getBlockY(); + _maxHeight = a.getY() - _minY; + _minY += 0.1; + + _mid = UtilAlg.getAverageLocation(Arrays.asList(a, b)); + } + + @Override + public void disable() + { + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 3, false, false)); + player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.getState() != GameState.Live) + { + return; + } + + for (Player player : getAllPlayers()) + { + if (player.getLocation().getBlock().isLiquid()) + { + player.teleport(_playersTeam.getSpawn()); + player.setFireTicks(0); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + event.AddMod(getGameType().getName(), "The Rope", 500, true); + } + + @EventHandler + public void updateRope(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + double xD = _maxHeight * Math.cos(_theta); + double yD = _maxHeight * Math.sin(_theta); + double yR = _maxHeight * Math.sin(_theta - Math.PI / 8); + + Location mid = _mid.clone().add(xD, yD - 0.2, 0); + + for (double z = -_zDiff; z <= _zDiff; z++) + { + mid.add(0, 0.3, z); + + UtilParticle.PlayParticleToAll(ParticleType.EXPLODE, mid, null, 0, 1, ViewDist.NORMAL); + + mid.subtract(0, 0.3, z); + } + + if (_mid.getY() + yR <= _minY) + { + for (Player player : getAlivePlayers()) + { + if (!UtilEnt.onBlock(player) || !Recharge.Instance.use(player, "Hit by Rope", 500, false, false)) + { + continue; + } + + player.playEffect(EntityEffect.HURT); + UtilAction.velocity(player, new Vector(1, 1, 0)); + } + } + + _theta += _thetaDelta; + + if (_theta > 2 * Math.PI) + { + _theta = 0; + _thetaDelta *= 1.05; + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/kingslime/KingSlime.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/kingslime/KingSlime.java new file mode 100644 index 000000000..5a6e9bd04 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/kingslime/KingSlime.java @@ -0,0 +1,263 @@ +package mineplex.game.nano.game.games.kingslime; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class KingSlime extends ScoredSoloGame +{ + + private static final int MAX_SLIMES = 30; + private static final int MAX_BALLS = 10; + private static final String SLIME_NAME = "Big Brian"; + + private Slime _king; + private Location _kingSpawn; + + private final Set _tinySlimes; + private List _tinySlimeSpawns; + + public KingSlime(NanoManager manager) + { + super(manager, GameType.KING_SLIME, new String[] + { + C.cGreen + SLIME_NAME + C.Reset + " is hungry!", + "Kill the " + C.cYellow + "Tiny Slimes" + C.Reset + " to get " + C.cGreen + "Slime Balls" + C.Reset + ".", + "Give the " + C.cGreen + "Slime Balls" + C.Reset + " to " + C.cGreen + SLIME_NAME + C.Reset + ".", + "The player with the most " + C.cYellow + "Balls Fed" + C.Reset + " wins." + }); + + _tinySlimes = new HashSet<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + _spectatorComponent.setDeathOut(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(90)); + } + + @Override + protected void parseData() + { + _kingSpawn = _mineplexWorld.getIronLocation("LIME"); + _tinySlimeSpawns = _mineplexWorld.getIronLocations("GREEN"); + } + + @Override + public void disable() + { + super.disable(); + + _tinySlimes.clear(); + _tinySlimeSpawns.clear(); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + _worldComponent.setCreatureAllowOverride(true); + + _king = _kingSpawn.getWorld().spawn(_kingSpawn, Slime.class); + + _king.setSize(2); + _king.setCustomName(C.cGreenB + SLIME_NAME); + _king.setCustomNameVisible(true); + + UtilEnt.vegetate(_king, true); + UtilEnt.ghost(_king, true, false); + UtilEnt.setFakeHead(_king, true); + + _worldComponent.setCreatureAllowOverride(false); + } + + @EventHandler + public void updateSlimes(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive() || _tinySlimeSpawns.isEmpty()) + { + return; + } + + _worldComponent.setCreatureAllowOverride(true); + + while (_tinySlimes.size() < MAX_SLIMES) + { + Location location = UtilAlg.Random(_tinySlimeSpawns); + + if (location == null) + { + break; + } + + Slime slime = location.getWorld().spawn(location, Slime.class); + + if (Math.random() < 0.05) + { + slime.setSize(2); + slime.setCustomName(C.cYellowB + "Power Slime"); + slime.setCustomNameVisible(true); + } + else + { + slime.setSize(1); + } + + _tinySlimes.add(slime); + } + + _worldComponent.setCreatureAllowOverride(false); + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + Entity entity = event.getEntity(); + + if (_tinySlimes.remove(entity)) + { + Player killer = event.getEntity().getKiller(); + + if (killer != null) + { + killer.getInventory().addItem(new ItemStack(Material.SLIME_BALL, (int) Math.pow(((Slime) entity).getSize(), 2))); + event.setDroppedExp(0); + event.getDrops().clear(); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void kingInteract(CustomDamageEvent event) + { + LivingEntity damagee = event.GetDamageeEntity(); + Player damager = event.GetDamagerPlayer(false); + + if (damagee.equals(_king)) + { + event.SetCancelled("King Damage"); + feed(damager); + } + else if (damager != null && damager.getInventory().contains(Material.SLIME_BALL, MAX_BALLS)) + { + event.SetCancelled("Too Many Balls"); + damager.sendMessage(F.main(getManager().getName(), "You can only hold a maximum of " + F.count(MAX_BALLS) + " balls.")); + } + } + + @EventHandler + public void playerInteract(PlayerInteractEntityEvent event) + { + if (!event.getRightClicked().equals(_king)) + { + return; + } + + feed(event.getPlayer()); + } + + private void feed(Player player) + { + if (player == null || !isLive()) + { + return; + } + + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null || itemStack.getType() != Material.SLIME_BALL) + { + return; + } + + int amount = itemStack.getAmount(); + + incrementScore(player, amount); + UtilTextBottom.display(C.cYellow + "+" + amount + C.cGreen + " Slime Ball" + (amount == 1 ? "" : "s"), player); + + player.setItemInHand(null); + + int total = getScores().values().stream() + .mapToInt(value -> value) + .sum(); + + int size = 2 + (total / 40); + + if (_king.getSize() != size) + { + _king.setSize(size); + _king.getWorld().playSound(_king.getLocation(), Sound.SLIME_WALK2, 2, 1); + UtilEnt.setPosition(_king, _kingSpawn); + + if (Math.random() > 0.5) + { + getManager().runSyncTimer(new BukkitRunnable() + { + float yaw = 0; + + @Override + public void run() + { + yaw += 5; + + if (yaw > 360) + { + cancel(); + yaw = 0; + } + + _kingSpawn.setYaw(yaw); + UtilEnt.CreatureLook(_king, yaw); + } + }, 0, 1); + } + else + { + UtilAction.velocity(_king, new Vector(0, 0.5, 0)); + } + } + else + { + _king.getWorld().playSound(_king.getLocation(), Sound.SLIME_WALK, 2, 1); + } + + player.getWorld().playEffect(player.getLocation().add(0, 1, 0), Effect.SLIME, 16); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/MicroBattle.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/MicroBattle.java new file mode 100644 index 000000000..987df7617 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/MicroBattle.java @@ -0,0 +1,208 @@ +package mineplex.game.nano.game.games.microbattle; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilItem; +import mineplex.core.common.util.UtilTime; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.TeamGame; +import mineplex.game.nano.game.components.player.GiveItemComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.games.microbattle.components.MapCourruptionComponent; +import mineplex.game.nano.game.games.microbattle.components.TeamArmourComponent; + +public class MicroBattle extends TeamGame +{ + + private static final long BARRIER_TIME = TimeUnit.SECONDS.toMillis(10); + + private final Set _glass = new HashSet<>(); + + public MicroBattle(NanoManager manager) + { + super(manager, GameType.MICRO_BATTLE, new String[] + { + "Gather some " + C.cGreen + "Blocks" + C.Reset + ".", + "The " + C.cAqua + "Glass Barrier" + C.Reset + " will disappear in " + C.cRed + "10 seconds" + C.Reset + ".", + "Be the " + C.cYellow + "Last Team" + C.Reset + " standing!" + }); + + _worldComponent + .setBlockBreak(true) + .setBlockPlace(true); + + _playerComponent + .setItemDropPickup(true) + .setHunger(true) + .setItemMovement(true); + + new GiveItemComponent(this) + .setItems(new ItemStack[] + { + new ItemBuilder(Material.IRON_SWORD) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.STONE_SPADE) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.STONE_PICKAXE) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.STONE_AXE) + .setUnbreakable(true) + .build(), + new ItemStack(Material.APPLE, 3) + }); + + new TeamArmourComponent(this); + + new MapCourruptionComponent(this) + .setRate(8) + .setEnableAfter(TimeUnit.SECONDS.toMillis(15), () -> announce(F.main(getManager().getName(), "The world beings to corrupt..."), Sound.ENDERDRAGON_GROWL)); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + getTeams().forEach(team -> + { + List alive = team.getAlivePlayers(); + + if (alive.isEmpty()) + { + return; + } + + scoreboard.write(team.getChatColour() + C.Bold + team.getName()); + scoreboard.write(alive.size() + " Alive"); + + scoreboard.writeNewLine(); + }); + + scoreboard.draw(); + }); + } + + @Override + protected void createTeams() + { + addTeam(new GameTeam(this, "Red", ChatColor.RED, Color.RED, DyeColor.RED, _mineplexWorld)); + addTeam(new GameTeam(this, "Yellow", ChatColor.YELLOW, Color.YELLOW, DyeColor.YELLOW, _mineplexWorld)); + addTeam(new GameTeam(this, "Green", ChatColor.GREEN, Color.LIME, DyeColor.LIME, _mineplexWorld)); + addTeam(new GameTeam(this, "Blue", ChatColor.AQUA, Color.AQUA, DyeColor.LIGHT_BLUE, _mineplexWorld)); + } + + @Override + protected void parseData() + { + for (Location location : _mineplexWorld.getSpongeLocations(String.valueOf(Material.GLASS.getId()))) + { + Block block = location.getBlock(); + + _glass.add(block); + block.setType(Material.STAINED_GLASS); + } + } + + @Override + public void disable() + { + _glass.clear(); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.FAST_DIGGING, Integer.MAX_VALUE, 0, false, false)); + } + + @EventHandler + public void playerDropItem(PlayerDropItemEvent event) + { + if (!isLive()) + { + return; + } + + ItemStack itemStack = event.getItemDrop().getItemStack(); + + if (UtilItem.isSword(itemStack)) + { + event.setCancelled(true); + } + } + + @EventHandler + public void updateHunger(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + for (Player player : getAlivePlayers()) + { + if (player.getFoodLevel() < 2) + { + player.setFoodLevel(2); + } + } + } + + @EventHandler + public void updateGlassBarrier(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER || !isLive() || _glass.isEmpty() || !UtilTime.elapsed(getStateTime(), BARRIER_TIME)) + { + return; + } + + _glass.forEach(block -> MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR)); + _glass.clear(); + } + + @EventHandler + public void blockBreak(BlockBreakEvent event) + { + if (_glass.contains(event.getBlock())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void itemSpawn(ItemSpawnEvent event) + { + if (event.getEntity().getItemStack().getType() == Material.FLINT) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/MapCourruptionComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/MapCourruptionComponent.java new file mode 100644 index 000000000..85aee36cd --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/MapCourruptionComponent.java @@ -0,0 +1,261 @@ +package mineplex.game.nano.game.games.microbattle.components; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +public class MapCourruptionComponent extends GameComponent +{ + + private static final Material CORRUPTION_BLOCK = Material.NETHERRACK; + + private final List _worldBlocks; + + private boolean _enabled; + private long _enableAfter; + private Runnable _onCrumble; + private int _rate = 4; + private int _y; + private boolean _sorted; + + public MapCourruptionComponent(Game game) + { + super(game, GameState.Prepare, GameState.Live); + + _worldBlocks = new ArrayList<>(20000); + } + + @Override + public void disable() + { + _worldBlocks.clear(); + } + + public MapCourruptionComponent setEnabled(boolean enabled) + { + _enabled = enabled; + return this; + } + + public boolean isEnabled() + { + return _enabled; + } + + public MapCourruptionComponent setEnableAfter(long enableAfter, Runnable onCrumble) + { + _enableAfter = enableAfter; + _onCrumble = onCrumble; + return this; + } + + public MapCourruptionComponent setRate(int rate) + { + _rate = rate; + return this; + } + + public long getTimeUntilCrumble() + { + return getGame().getStateTime() + _enableAfter - System.currentTimeMillis(); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + _y = getGame().getMineplexWorld().getMin().getBlockY(); + } + + @EventHandler + public void parseMap(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST || _y > getGame().getMineplexWorld().getMax().getBlockY()) + { + return; + } + + MineplexWorld mineplexWorld = getGame().getMineplexWorld(); + World world = mineplexWorld.getWorld(); + int minX = mineplexWorld.getMin().getBlockX(), maxX = mineplexWorld.getMax().getBlockX(); + int minZ = mineplexWorld.getMin().getBlockZ(), maxZ = mineplexWorld.getMax().getBlockZ(); + + for (int x = minX; x < maxX; x++) + { + for (int z = minZ; z < maxZ; z++) + { + Block block = world.getBlockAt(x, _y, z); + + if (block.getType() == Material.AIR || block.isLiquid()) + { + continue; + } + + _worldBlocks.add(block); + } + } + + _y++; + } + + private void addWorldBlock(Block block) + { + if (block.getWorld().equals(getGame().getMineplexWorld().getWorld())) + { + _sorted = false; + _worldBlocks.add(block); + } + } + + @EventHandler + public void crumbleStart(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || !getGame().isLive() || _enabled || !UtilTime.elapsed(getGame().getStateTime(), _enableAfter)) + { + return; + } + + _enabled = true; + + if (_onCrumble != null) + { + _onCrumble.run(); + } + } + + @EventHandler + public void crumble(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !getGame().isLive() || _worldBlocks.isEmpty() || !_enabled) + { + return; + } + + if (!_sorted) + { + Location mid = getGame().getSpectatorLocation(); + + _worldBlocks.sort((o1, o2) -> + { + if (o1.getX() == o2.getX() && o1.getZ() == o2.getZ()) + { + return Integer.compare(o1.getY(), o2.getY()); + } + + return Double.compare(UtilMath.offsetSquared(mid, o1.getLocation().add(0.5, 0.5, 0.5)), UtilMath.offsetSquared(mid, o2.getLocation().add(0.5, 0.5, 0.5))); + }); + _sorted = true; + } + + for (int i = 0; i < _rate; i++) + { + if (_worldBlocks.isEmpty()) + { + return; + } + + Block bestBlock = _worldBlocks.remove(0); + Material material = bestBlock.getType(); + + if (material == Material.AIR || material == CORRUPTION_BLOCK) + { + continue; + } + + if (material == Material.WOODEN_DOOR || material == Material.IRON_DOOR_BLOCK) + { + MapUtil.QuickChangeBlockAt(bestBlock.getRelative(BlockFace.UP).getLocation(), Material.AIR); + MapUtil.QuickChangeBlockAt(bestBlock.getLocation(), Material.AIR); + continue; + } + + MapUtil.QuickChangeBlockAt(bestBlock.getLocation(), CORRUPTION_BLOCK); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void blockPlace(BlockPlaceEvent event) + { + addWorldBlock(event.getBlock()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void blockPlace(BlockBreakEvent event) + { + Block block = event.getBlock(); + + if (block.getType() == CORRUPTION_BLOCK) + { + event.setCancelled(true); + } + else + { + _worldBlocks.remove(block); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void blockPhysics(BlockPhysicsEvent event) + { + addWorldBlock(event.getBlock()); + } + + @EventHandler + public void corruptionDamage(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isEnabled()) + { + return; + } + + playerLoop: + for (Player player : getGame().getAlivePlayers()) + { + Pair box = UtilEnt.getSideStandingBox(player); + Location min = box.getLeft(), max = box.getRight(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) + { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) + { + Block block = player.getLocation().add(x, -0.5, z).getBlock(); + + if (block.getType() == CORRUPTION_BLOCK) + { + getGame().getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 2, false, true, true, getGame().getGameType().getName(), "Corruption"); + continue playerLoop; + } + } + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/TeamArmourComponent.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/TeamArmourComponent.java new file mode 100644 index 000000000..0bec68048 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/microbattle/components/TeamArmourComponent.java @@ -0,0 +1,78 @@ +package mineplex.game.nano.game.games.microbattle.components; + +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilItem; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.game.nano.game.Game; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.GameComponent; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; + +public class TeamArmourComponent extends GameComponent +{ + + public TeamArmourComponent(Game game) + { + super(game, GameState.Prepare, GameState.Live); + } + + @Override + public void disable() + { + + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + GameTeam team = event.getTeam(); + Color colour = team.getColour(); + String name = team.getChatColour() + "Team Armor"; + + player.getInventory().setArmorContents(new ItemStack[] + { + new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(name) + .setColor(colour) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(name) + .setColor(colour) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(name) + .setColor(colour) + .setUnbreakable(true) + .build(), + new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(name) + .setColor(colour) + .setUnbreakable(true) + .build() + }); + player.getInventory().setItem(8, new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(team.getChatColour() + C.Bold + team.getName()) + .setColor(colour) + .build()); + } + + @EventHandler(ignoreCancelled = true) + public void inventoryClick(InventoryClickEvent event) + { + if (UtilItem.isLeatherProduct(event.getCurrentItem())) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/mobfarm/MobFarm.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/mobfarm/MobFarm.java new file mode 100644 index 000000000..b3348c4b5 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/mobfarm/MobFarm.java @@ -0,0 +1,241 @@ +package mineplex.game.nano.game.games.mobfarm; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.components.player.GiveItemComponent; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class MobFarm extends ScoredSoloGame +{ + + private static final int MAX_MOBS = 30; + private static final int MAX_MINUS_TICKS = 400; + + private enum MobType + { + + CHICKEN(EntityType.CHICKEN, 1, ChatColor.WHITE, 1), + PIG(EntityType.PIG, 3, ChatColor.LIGHT_PURPLE, 6), + COW(EntityType.COW, 5, ChatColor.GOLD, 10), + + ; + + final EntityType Type; + final int Points; + final ChatColor Colour; + final int Health; + + MobType(EntityType type, int points, ChatColor colour, int health) + { + Type = type; + Points = points; + Colour = colour; + Health = health; + } + } + + private final Map _mobs; + private List _mobSpawns; + + public MobFarm(NanoManager manager) + { + super(manager, GameType.MOB_FARM, new String[] + { + "Kill " + C.cYellow + "Mobs" + C.Reset + " to earn points.", + C.cGreen + "Bigger" + C.Reset + " mobs give more points.", + "Watch out for " + C.cRed + "Minus" + C.Reset + " mobs. They will reduce your score.", + C.cYellow + "Most points" + C.Reset + " wins!" + }); + + _mobs = new HashMap<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(75)); + + new GiveItemComponent(this) + .setItems(new ItemStack[] + { + new ItemBuilder(Material.WOOD_SWORD) + .setUnbreakable(true) + .build() + }); + } + + @Override + protected void parseData() + { + _mobSpawns = _mineplexWorld.getIronLocations("LIME"); + } + + @Override + public void disable() + { + super.disable(); + + _mobSpawns.clear(); + } + + @EventHandler + public void updateMobs(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive()) + { + return; + } + + _mobs.entrySet().removeIf(entry -> + { + LivingEntity entity = entry.getKey(); + + if (entry.getValue() && entity.getTicksLived() > MAX_MINUS_TICKS) + { + entity.setHealth(0); + return true; + } + + return false; + }); + + while (_mobs.size() < MAX_MOBS) + { + MobType mobType = getRandomMob(); + Location location = UtilAlg.Random(_mobSpawns); + + if (location == null) + { + return; + } + + _worldComponent.setCreatureAllowOverride(true); + + location.setYaw(UtilMath.r(360)); + + LivingEntity entity = (LivingEntity) location.getWorld().spawnEntity(location, mobType.Type); + + if (Math.random() < 0.1) + { + entity.setCustomName(C.cRedB + "MINUS 50%"); + entity.setMaxHealth(1); + _mobs.put(entity, true); + } + else + { + entity.setCustomName(mobType.Colour + C.Bold + "+" + mobType.Points + " Point" + (mobType.Points == 1 ? "" : "s")); + entity.setMaxHealth(mobType.Health); + _mobs.put(entity, false); + } + + entity.setCustomNameVisible(true); + entity.setHealth(entity.getMaxHealth()); + } + } + + @EventHandler(ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + if (_mobs.containsKey(event.GetDamageeEntity())) + { + event.GetDamageeEntity().addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false, false)); + } + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + LivingEntity entity = event.getEntity(); + Boolean minus = _mobs.remove(entity); + + if (minus != null) + { + event.getDrops().clear(); + event.setDroppedExp(0); + + Player killer = entity.getKiller(); + + if (killer == null) + { + return; + } + + if (minus) + { + getScores().put(killer, getScores().getOrDefault(killer, 0) / 2); + killer.playSound(entity.getLocation(), Sound.SILVERFISH_KILL, 1, 1); + } + else + { + incrementScore(killer, getPointsFor(entity)); + } + } + } + + @EventHandler + public void end(GameStateChangeEvent event) + { + if (event.getState() != GameState.End) + { + return; + } + + _mobs.keySet().forEach(entity -> entity.setHealth(0)); + } + + private MobType getRandomMob() + { + double random = Math.random(); + + if (random > 0.5) + { + return MobType.CHICKEN; + } + else if (random > 0.1) + { + return MobType.PIG; + } + + return MobType.COW; + } + + private int getPointsFor(LivingEntity entity) + { + for (MobType type : MobType.values()) + { + if (type.Type == entity.getType()) + { + return type.Points; + } + } + + return 0; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/musicminecart/MusicMinecarts.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/musicminecart/MusicMinecarts.java new file mode 100644 index 000000000..e83bd5649 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/musicminecart/MusicMinecarts.java @@ -0,0 +1,294 @@ +package mineplex.game.nano.game.games.musicminecart; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.vehicle.VehicleDamageEvent; +import org.bukkit.event.vehicle.VehicleExitEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.noteblock.NBSReader; +import mineplex.core.noteblock.NotePlayer; +import mineplex.core.noteblock.NoteSong; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; + +public class MusicMinecarts extends SoloGame +{ + + private final Set _minecarts; + private final NotePlayer _notePlayer; + + private Location _center; + private List _floor; + private double _floorRadiusInitial, _floorRadius; + private boolean _spawned; + private int _startingPlayers; + + public MusicMinecarts(NanoManager manager) + { + super(manager, GameType.MUSIC_MINECARTS, new String[] + { + "Musical Chairs!", + "When the music " + C.cRed + "Stops" + C.Reset + " get in a " + C.cYellow + "Minecart", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + + _minecarts = new HashSet<>(); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + NoteSong song; + + try + { + song = NBSReader.loadSong(".." + File.separator + ".." + File.separator + "update" + File.separator + "songs" + File.separator + "bebop.nbs"); + } + catch (FileNotFoundException e) + { + song = null; + e.printStackTrace(); + } + + if (song != null) + { + _notePlayer = new NotePlayer(manager.getPlugin(), song, null, 0.5F, true); + _notePlayer.setPaused(true); + } + else + { + _notePlayer = null; + } + } + + @Override + protected void parseData() + { + _center = _mineplexWorld.getIronLocation("RED"); + + Block toSet = _center.getBlock().getRelative(BlockFace.DOWN); + Material floorType = toSet.getType(); + byte floorData = toSet.getData(); + + toSet.setType(Material.AIR); + + _floor = _mineplexWorld.getIronLocations("ORANGE"); + _floor.sort((o1, o2) -> Double.compare(UtilMath.offset2dSquared(_center, o2), UtilMath.offset2dSquared(_center, o1))); + _floor.forEach(location -> MapUtil.QuickChangeBlockAt(location, floorType, floorData)); + _floorRadius = UtilMath.offset2d(_center, _floor.get(0)); + _floorRadiusInitial = _floorRadius; + } + + @Override + public void disable() + { + _minecarts.clear(); + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + event.getPlayersToInform().clear(); + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.getState() != GameState.Live) + { + return; + } + + _startingPlayers = getAlivePlayers().size(); + runRound(true); + } + + private void runRound(boolean first) + { + updateArenaSize(); + + int spawnAt = UtilMath.rRange(4, 10) + (first ? 5 : 0); + int destroyAt = 15 + spawnAt; + + if (_notePlayer != null) + { + _notePlayer.setPaused(false); + } + + getManager().runSyncTimer(new BukkitRunnable() + { + int seconds = 0; + + @Override + public void run() + { + if (++seconds == spawnAt) + { + _spawned = true; + + if (_notePlayer != null) + { + _notePlayer.setPaused(true); + } + + UtilTextMiddle.display(null, "Get in a " + C.cRed + "Minecart", 0, 20, 10, getAlivePlayers().toArray(new Player[0])); + + int toSpawn = (int) Math.ceil(getAlivePlayers().size() / 2D); + FireworkEffect effect = FireworkEffect.builder() + .with(Type.BALL) + .withColor(Color.RED) + .build(); + + for (int i = 0; i < toSpawn; i++) + { + Location location = UtilAlg.Random(_floor); + + if (location == null) + { + return; + } + + location = location.clone().add(0, 8, 0); + + _minecarts.add(location.getWorld().spawn(location, Minecart.class)); + + if (i < 5) + { + UtilFirework.playFirework(location, effect); + } + } + } + + if (!_spawned) + { + return; + } + + boolean end = true; + + for (Minecart minecart : _minecarts) + { + if (minecart.getPassenger() == null) + { + end = false; + } + } + + if (end || seconds == destroyAt) + { + _spawned = false; + + for (Player player : getAlivePlayers()) + { + if (player.getVehicle() != null) + { + player.leaveVehicle(); + continue; + } + + getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 500, false, true, true, getGameType().getName(), "Too Slow"); + } + + _minecarts.forEach(Entity::remove); + _minecarts.clear(); + cancel(); + + if (isLive()) + { + runRound(false); + } + } + } + }, 0, 20); + } + + private void updateArenaSize() + { + double radius = Math.max(_floorRadiusInitial * ((double) getAlivePlayers().size() / _startingPlayers), 10); + + if (_floorRadius > radius) + { + announce(F.main(getManager().getName(), "Watch out! The arena is getting smaller!")); + + getManager().runSyncTimer(new BukkitRunnable() + { + @Override + public void run() + { + if (!isLive() || _floorRadius <= radius) + { + cancel(); + return; + } + + Iterator iterator = _floor.iterator(); + + while (iterator.hasNext()) + { + Location location = iterator.next(); + + if (UtilMath.offset2d(_center, location) <= _floorRadius) + { + break; + } + + MapUtil.QuickChangeBlockAt(location, Material.AIR); + iterator.remove(); + } + + _floorRadius--; + + for (Player player : _mineplexWorld.getWorld().getPlayers()) + { + player.playSound(player.getLocation(), Sound.CHICKEN_EGG_POP, 1, 0.5F); + } + } + }, 0, 4); + } + } + + @EventHandler + public void vehicleLeave(VehicleExitEvent event) + { + if (_spawned) + { + event.setCancelled(true); + } + } + + @EventHandler + public void vehicleDamage(VehicleDamageEvent event) + { + event.setCancelled(true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/oits/SnowballTrouble.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/oits/SnowballTrouble.java new file mode 100644 index 000000000..46aebf5a6 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/oits/SnowballTrouble.java @@ -0,0 +1,138 @@ +package mineplex.game.nano.game.games.oits; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.minecraft.game.core.combat.CombatComponent; +import mineplex.minecraft.game.core.combat.DeathMessageType; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class SnowballTrouble extends ScoredSoloGame +{ + + private static final int MAX_BALLS = 5; + + private final ItemStack _snowball; + + public SnowballTrouble(NanoManager manager) + { + super(manager, GameType.SNOWBALL_TROUBLE, new String[] + { + "Snowballs are " + C.cYellow + "One-Hit" + C.Reset + "!", + "You have " + C.cGreen + "Infinite Respawns" + C.Reset + ".", + C.cYellow + "Most kills" + C.Reset + " wins!" + }); + + _snowball = new ItemStack(Material.SNOW_BALL); + + _prepareComponent.setPrepareFreeze(false); + + _teamComponent.setRespawnRechargeTime(500); + + _damageComponent.setFall(false); + + _spectatorComponent.setDeathOut(false); + + _endComponent.setTimeout(TimeUnit.SECONDS.toMillis(100)); + } + + @Override + protected void parseData() + { + + } + + @Override + public void disable() + { + + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + for (Player player : getAlivePlayers()) + { + incrementScore(player, 0); + } + } + + @Override + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + event.getPlayer().getInventory().addItem(_snowball); + } + + @EventHandler + public void updateGiveBalls(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER || !isLive()) + { + return; + } + + for (Player player : getAlivePlayers()) + { + if (!player.getInventory().contains(Material.SNOW_BALL, MAX_BALLS)) + { + player.getInventory().addItem(_snowball); + } + } + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(); + + if (damagee == null || !(event.GetProjectile() instanceof Snowball)) + { + return; + } + + event.AddMod(event.GetDamagerPlayer(true).getName(), "Snowball", 20, true); + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + event.SetBroadcastType(DeathMessageType.Simple); + + CombatComponent killerComp = event.GetLog().GetKiller(); + + if (killerComp == null) + { + return; + } + + Player killer = UtilPlayer.searchExact(killerComp.getUniqueIdOfEntity()); + + if (killer == null) + { + return; + } + + incrementScore(killer, 1); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/parkour/Parkour.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/parkour/Parkour.java new file mode 100644 index 000000000..a899b00bc --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/parkour/Parkour.java @@ -0,0 +1,321 @@ +package mineplex.game.nano.game.games.parkour; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GamePlacements; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.PlayerGameApplyEvent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class Parkour extends SoloGame +{ + + private final Comparator _sorter = (o1, o2) -> + { + boolean o1F = o1.FinishedAt > 0, o2F = o2.FinishedAt > 0; + + if (o1F && o2F) + { + return Long.compare(o1.FinishedAt, o2.FinishedAt); + } + else if (o1F) + { + return -1; + } + else if (o2F) + { + return 1; + } + + return Integer.compare(o2.Index, o1.Index); + }; + private final List _places; + private final List _path; + private final List _checkpointIndexes; + + private final long _timeout; + private boolean _oneFinished; + + public Parkour(NanoManager manager) + { + super(manager, GameType.PARKOUR, new String[] + { + C.cYellow + "Parkour" + C.Reset + " your way to the " + C.cGreen + "Goal" + C.Reset + ".", + C.cRed + "Dying" + C.Reset + " returns you back to the " + C.cGreen + "Start" + C.Reset + "!", + C.cYellow + "First player" + C.Reset + " to the end wins!" + }); + + _places = new ArrayList<>(); + _path = new ArrayList<>(); + _checkpointIndexes = new ArrayList<>(); + + _timeout = TimeUnit.MINUTES.toMillis(4); + _endComponent.setTimeout(_timeout); + + _damageComponent + .setPvp(false) + .setFall(false); + + _spectatorComponent.setDeathOut(false); + + _scoreboardComponent + .setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Players"); + + for (ParkourPlace place : _places.subList(0, Math.min(12, _places.size()))) + { + Player other = place.Parkourer; + String colour = ""; + + if (other.equals(player)) + { + colour = C.cGreen; + } + else if (place.FinishedAt > 0) + { + colour = C.cYellow; + } + + scoreboard.write(colour + other.getName()); + } + + scoreboard.writeNewLine(); + + scoreboard.draw(); + }) + .setSetupSettingsConsumer((player, team, scoreboardTeam) -> scoreboardTeam.setCanSeeFriendlyInvisibles(false)); + } + + @Override + protected void parseData() + { + List path = _mineplexWorld.getIronLocations("BLACK"); + List checkpoints = _mineplexWorld.getIronLocations("YELLOW"); + List lookAt = _mineplexWorld.getIronLocations("ORANGE"); + Location start = _playersTeam.getSpawn(); + + path.addAll(checkpoints); + + while (!path.isEmpty()) + { + start = UtilAlg.findClosest(start, path); + + if (checkpoints.contains(start)) + { + _checkpointIndexes.add(_path.size()); + start.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(start, UtilAlg.findClosest(start, lookAt)))); + } + + _path.add(start); + path.remove(start); + } + } + + @Override + public boolean endGame() + { + return false; + } + + @Override + public void disable() + { + _places.clear(); + _path.clear(); + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + event.getPlayersToInform().clear(); + } + + @EventHandler + public void playerApply(PlayerGameApplyEvent event) + { + if (!isLive()) + { + return; + } + + Player player = event.getPlayer(); + + for (ParkourPlace parkourPlace : _places) + { + if (player.equals(parkourPlace.Parkourer) && parkourPlace.CheckpointIndex >= 0) + { + event.setRespawnLocation(_path.get(parkourPlace.CheckpointIndex)); + } + } + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + + for (ParkourPlace parkourPlace : _places) + { + if (parkourPlace.Parkourer.equals(player)) + { + return; + } + } + + _places.add(new ParkourPlace(player)); + } + + @EventHandler(priority = EventPriority.LOW) + public void sortPlaces(UpdateEvent event) + { + if (!isLive()) + { + return; + } + + if (event.getType() == UpdateType.FAST) + { + _places.sort(_sorter); + } + else if (event.getType() == UpdateType.FASTER) + { + _places.forEach(parkourPlace -> + { + if (parkourPlace.FinishedAt > 0) + { + return; + } + + Player player = parkourPlace.Parkourer; + Location location = player.getLocation(); + int current = parkourPlace.Index; + + for (int i = 0; i < _path.size(); i++) + { + if (!isNearPath(location, i)) + { + continue; + } + + if (current + 3 < i) + { + getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 500, false, true, true, getGameType().getName(), "Cheating"); + return; + } + + int checkpointIndex = _checkpointIndexes.indexOf(i); + + if (checkpointIndex >= 0 && parkourPlace.CheckpointIndex < i) + { + player.playSound(player.getLocation(), Sound.FIREWORK_LAUNCH, 1, 1); + UtilTextMiddle.display("", C.cYellowB + "Checkpoint!", 0, 30, 20, player); + parkourPlace.CheckpointIndex = i; + } + else if (i == _path.size() - 1) + { + addSpectator(player, false, false); + parkourPlace.FinishedAt = System.currentTimeMillis(); + + announce(F.main(getManager().getName(), F.name(player.getName()) + " finished the course in " + F.time(UtilTime.MakeStr(parkourPlace.FinishedAt - getStateTime())) + "!"), null); + UtilTextMiddle.display(C.cGreen + "End!", "You reached the end of the course!", 0, 50, 20, player); + + if (!_oneFinished) + { + _oneFinished = true; + + long elapsed = parkourPlace.FinishedAt - getStateTime(); + long left = _timeout - elapsed; + long reduceTo = TimeUnit.SECONDS.toMillis(30); + + if (left > reduceTo) + { + // Set the game to timeout in 30 seconds + _endComponent.setTimeout(elapsed + reduceTo); + announce(F.main(getManager().getName(), "The game will now end in " + F.time(UtilTime.MakeStr(reduceTo)) + "!")); + } + } + } + + parkourPlace.Index = i; + } + }); + } + } + + private boolean isNearPath(Location location, int pathIndex) + { + if (pathIndex >= _path.size()) + { + return false; + } + + return UtilMath.offsetSquared(location, _path.get(pathIndex)) < 16; + } + + @Override + protected GamePlacements createPlacements() + { + _playersTeam.getActualPlaces().clear(); + _places.forEach(parkourPlace -> _playersTeam.addPlacementBottom(parkourPlace.Parkourer)); + + return GamePlacements.fromTeamPlacements(_playersTeam.getActualPlaces()); + } + + @EventHandler + public void playerOut(PlayerStateChangeEvent event) + { + if (!event.isAlive()) + { + _places.removeIf(parkourPlace -> parkourPlace.Parkourer.equals(event.getPlayer())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + event.AddMod(getGameType().getName(), 500); + } + + private class ParkourPlace + { + + final Player Parkourer; + int Index, CheckpointIndex = -1; + long FinishedAt; + + ParkourPlace(Player parkourer) + { + Parkourer = parkourer; + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Challenge.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Challenge.java new file mode 100644 index 000000000..5e7fc768b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Challenge.java @@ -0,0 +1,226 @@ +package mineplex.game.nano.game.games.quick; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTextTop; +import mineplex.core.common.util.UtilTime; +import mineplex.core.lifetimes.Lifetime; +import mineplex.core.lifetimes.Lifetimed; +import mineplex.core.lifetimes.ListenerComponent; +import mineplex.core.lifetimes.SimpleLifetime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.components.Disposable; +import mineplex.game.nano.game.event.PlayerDeathOutEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +public abstract class Challenge extends ListenerComponent implements Lifetimed, Disposable +{ + + private final SimpleLifetime _lifetime = new SimpleLifetime(); + + protected final Quick _game; + private final ChallengeType _challengeType; + protected final ChallengeWinConditions _winConditions; + + protected List _players; + protected long _startTime; + protected long _timeout = TimeUnit.SECONDS.toMillis(10); + private boolean _playerWon; + + protected boolean _pvp; + + public Challenge(Quick game, ChallengeType challengeType) + { + _game = game; + _challengeType = challengeType; + _winConditions = new ChallengeWinConditions(); + _lifetime.register(this); + } + + public abstract void challengeSelect(); + + public void start() + { + _startTime = System.currentTimeMillis(); + _players = _game.getAlivePlayers(); + _lifetime.start(); + + _players.forEach(player -> _game.respawnPlayer(player, _game.getPlayersTeam())); + + challengeSelect(); + + UtilTextMiddle.display("", C.cYellow + _challengeType.getDescription(), 0, 40, 10, UtilServer.getPlayers()); + _game.announce("", null); + _game.announce(" " + C.cYellowB + "Challenge! " + C.Reset + _challengeType.getDescription(), null); + _game.announce("", null); + } + + public void end() + { + disable(); + + for (Entity entity : _game.getMineplexWorld().getWorld().getEntities()) + { + if (entity instanceof Player) + { + continue; + } + + entity.remove(); + } + + completeRemaining(); + + _players.clear(); + _lifetime.end(); + } + + protected void completeRemaining() + { + for (Player player : _game.getAlivePlayers()) + { + if (_winConditions.isTimeoutWin()) + { + completePlayer(player, true); + } + else + { + failPlayer(player, true); + } + } + } + + public void completePlayer(Player player, boolean out) + { + if (_players.remove(player)) + { + UtilTextMiddle.display("", C.cGreen + "You completed the challenge!", 0, 30, 10, player); + player.sendMessage(F.main(_game.getManager().getName(), "You completed the challenge.")); + _game.incrementScore(player, 1); + + if (out) + { + _game.onOut(player, true); + } + + player.playSound(player.getLocation(), Sound.VILLAGER_YES, 1, 1); + } + + if (!_playerWon && _winConditions.isTimeoutAfterFirst()) + { + _playerWon = true; + + _game.announce(F.main(_game.getManager().getName(), "A player has completed the challenge. " + F.time("3 Seconds") + " left."), Sound.NOTE_STICKS); + _game.getManager().runSyncLater(() -> + { + if (isRunning()) + { + end(); + } + }, 3 * 20); + } + } + + public void failPlayer(Player player, boolean out) + { + if (_players.remove(player)) + { + UtilTextMiddle.display("", C.cRed + "You failed the challenge!", 0, 30, 10, player); + player.sendMessage(F.main(_game.getManager().getName(), "You failed the challenge.")); + + if (out) + { + _game.onOut(player, false); + } + + player.playSound(player.getLocation(), Sound.VILLAGER_NO, 1, 1); + } + } + + public boolean isParticipating(Player player) + { + return _players.contains(player); + } + + protected boolean isRunning() + { + return _lifetime.isActive() && _game.isLive(); + } + + protected boolean inArena(Block block) + { + return inArena(block.getLocation().add(0.5, 0.5, 0.5)); + } + + protected boolean inArena(Location location) + { + return UtilAlg.inBoundingBox(location, _game.getRedPoints().get(0), _game.getRedPoints().get(1)); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() == UpdateType.SEC) + { + UtilTextBottom.display(C.cYellow + _challengeType.getDescription(), UtilServer.getPlayers()); + } + else if (event.getType() == UpdateType.FASTER) + { + if (_players.isEmpty() || UtilTime.elapsed(_startTime, _timeout) || (_winConditions.isLastOne() && _players.size() == 1)) + { + end(); + } + else + { + long diff = System.currentTimeMillis() - _startTime; + + UtilTextTop.displayProgress(C.mTime + UtilTime.MakeStr(_timeout - diff), 1 - (double) diff / _timeout, UtilServer.getPlayers()); + } + } + } + + @EventHandler + public void playerOut(PlayerDeathOutEvent event) + { + Player player = event.getPlayer(); + + event.setCancelled(true); + event.setShouldRespawn(false); + failPlayer(player, true); + } + + @EventHandler + public void playerOut(PlayerStateChangeEvent event) + { + if (!event.isAlive()) + { + _players.remove(event.getPlayer()); + } + } + + boolean isPvp() + { + return _pvp; + } + + @Override + public Lifetime getLifetime() + { + return _lifetime; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeSetCommand.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeSetCommand.java new file mode 100644 index 000000000..cfec24f79 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeSetCommand.java @@ -0,0 +1,41 @@ +package mineplex.game.nano.game.games.quick; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.F; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.games.quick.Quick.Perm; + +public class ChallengeSetCommand extends CommandBase +{ + + ChallengeSetCommand(NanoManager plugin) + { + super(plugin, Perm.CHALLENGE_SET_COMMAND, "chalset"); + } + + @Override + public void Execute(Player caller, String[] args) + { + Quick game = (Quick) Plugin.getGame(); + + try + { + List challenges = Arrays.stream(args) + .map(arg -> ChallengeType.valueOf(arg.toUpperCase())) + .collect(Collectors.toList()); + + caller.sendMessage(F.main(Plugin.getName(), "Set the challenges to: " + challenges)); + game.setChallenges(challenges); + } + catch (Exception e) + { + caller.sendMessage(F.main(Plugin.getName(), "Invalid ChallengeType.")); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeType.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeType.java new file mode 100644 index 000000000..320b46f6f --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeType.java @@ -0,0 +1,67 @@ +package mineplex.game.nano.game.games.quick; + +import mineplex.game.nano.game.games.quick.challenges.ChallengeAvoidTNT; +import mineplex.game.nano.game.games.quick.challenges.ChallengeBlockSnake; +import mineplex.game.nano.game.games.quick.challenges.ChallengeCraftItem; +import mineplex.game.nano.game.games.quick.challenges.ChallengeCrouch; +import mineplex.game.nano.game.games.quick.challenges.ChallengeEnchantItem; +import mineplex.game.nano.game.games.quick.challenges.ChallengeFood; +import mineplex.game.nano.game.games.quick.challenges.ChallengeIgniteTNT; +import mineplex.game.nano.game.games.quick.challenges.ChallengeIntoVoid; +import mineplex.game.nano.game.games.quick.challenges.ChallengePlatform; +import mineplex.game.nano.game.games.quick.challenges.ChallengePole; +import mineplex.game.nano.game.games.quick.challenges.ChallengePunchAPig; +import mineplex.game.nano.game.games.quick.challenges.ChallengeRedBlocks; +import mineplex.game.nano.game.games.quick.challenges.ChallengeSlimeJump; +import mineplex.game.nano.game.games.quick.challenges.ChallengeSpeedBridge; +import mineplex.game.nano.game.games.quick.challenges.ChallengeSpleef; +import mineplex.game.nano.game.games.quick.challenges.ChallengeStandStill; +import mineplex.game.nano.game.games.quick.challenges.ChallengeSumo; +import mineplex.game.nano.game.games.quick.challenges.ChallengeThrowEggs; +import mineplex.game.nano.game.games.quick.challenges.ChallengeZombies; + +public enum ChallengeType +{ + + STAND_STILL(ChallengeStandStill.class, "Don't Move!"), + INTO_VOID(ChallengeIntoVoid.class, "Jump into the Void!"), + SUMO(ChallengeSumo.class, "Knock other players off the platform!"), + CRAFT_ITEM(ChallengeCraftItem.class, "Craft the item shown!"), + ENCHANT_ITEM(ChallengeEnchantItem.class, "Enchant a sword"), + RED_BLOCKS(ChallengeRedBlocks.class, "Don't fall into the void!"), + POLE(ChallengePole.class, "Get as high as you can!"), + CROUCH(ChallengeCrouch.class, "Crouch/Sneak!"), + ZOMBIES(ChallengeZombies.class, "Survive the Zombie Hoard!"), + SPLEEF(ChallengeSpleef.class, "Spleef other players into the void!"), + BLOCK_SNAKE(ChallengeBlockSnake.class, "Avoid the Block Snake!"), + THROW_EGGS(ChallengeThrowEggs.class, "Throw all your eggs!"), + PLATFORM(ChallengePlatform.class, "Get on the Platform!"), + AVOID_TNT(ChallengeAvoidTNT.class, "Avoid the falling TNT!"), + SPEED_BRIDGE(ChallengeSpeedBridge.class, "Bridge over to the other side!"), + FOOD(ChallengeFood.class, "Eat until you get full hunger!"), + SLIME_JUMP(ChallengeSlimeJump.class, "Get on the emerald blocks!"), + PUNCH_A_PIG(ChallengePunchAPig.class, "Punch 5 Pigs!"), + IGNITE_TNT(ChallengeIgniteTNT.class, "Ignite the TNT!"), + + + ; + + private final Class _challengeClass; + private final String _description; + + ChallengeType(Class challengeClass, String description) + { + _challengeClass = challengeClass; + _description = description; + } + + public Class getChallengeClass() + { + return _challengeClass; + } + + public String getDescription() + { + return _description; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeWinConditions.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeWinConditions.java new file mode 100644 index 000000000..f50a706fa --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/ChallengeWinConditions.java @@ -0,0 +1,42 @@ +package mineplex.game.nano.game.games.quick; + +public class ChallengeWinConditions +{ + + private boolean _lastOne, _timeoutWin; + private boolean _timeoutAfterFirst; + + public ChallengeWinConditions setLastOne(boolean lastOne) + { + setTimeoutWin(true); + _lastOne = lastOne; + return this; + } + + public boolean isLastOne() + { + return _lastOne; + } + + public ChallengeWinConditions setTimeoutWin(boolean timeoutWin) + { + _timeoutWin = timeoutWin; + return this; + } + + public boolean isTimeoutWin() + { + return _timeoutWin; + } + + public ChallengeWinConditions setTimeoutAfterFirst(boolean firstHalfWin) + { + _timeoutAfterFirst = firstHalfWin; + return this; + } + + public boolean isTimeoutAfterFirst() + { + return _timeoutAfterFirst; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Quick.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Quick.java new file mode 100644 index 000000000..f73fdb832 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/Quick.java @@ -0,0 +1,301 @@ +package mineplex.game.nano.game.games.quick; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; + +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.command.CommandCenter; +import mineplex.core.common.block.schematic.Schematic; +import mineplex.core.common.block.schematic.UtilSchematic; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.NanoPlayer; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.components.player.NightVisionComponent; +import mineplex.game.nano.game.event.PlayerDeathOutEvent; + +public class Quick extends ScoredSoloGame +{ + + public enum Perm implements Permission + { + CHALLENGE_SET_COMMAND + } + + private static final int CHALLENGES = 8; + + private final List _challengeTypes; + private final ChallengeSetCommand _command; + + private Location _center; + private Location _winnersLocation, _losersLocation; + private Location _arenaPaste; + private Schematic _arena; + private int _arenaSize; + + private Challenge _challenge; + private boolean _creating, _delay; + + public Quick(NanoManager manager) + { + super(manager, GameType.QUICK, new String[] + { + "You will be given " + C.cYellow + "Challenges" + C.Reset + ".", + "Complete them as " + C.cGreen + "Quickly" + C.Reset + " as you can.", + C.cYellow + "Most challenges completed" + C.Reset + " wins!" + }); + + PermissionGroup.ADMIN.setPermission(Perm.CHALLENGE_SET_COMMAND, true, true); + + _challengeTypes = new ArrayList<>(Arrays.asList(ChallengeType.values())); + _command = new ChallengeSetCommand(manager); + CommandCenter.Instance.addCommand(_command); + + _prepareComponent.setPrepareFreeze(false); + + _playerComponent + .setHunger(true) + .setItemMovement(true); + + _worldComponent.setBlockInteract(true); + + _endComponent.setTimeout(-1); + + new NightVisionComponent(this); + + while (_challengeTypes.size() > CHALLENGES) + { + _challengeTypes.remove(UtilMath.r(_challengeTypes.size())); + } + } + + @Override + public void disable() + { + super.disable(); + + if (_challenge != null && _challenge.getLifetime().isActive()) + { + _challenge.end(); + } + + CommandCenter.Instance.removeCommand(_command); + } + + @Override + protected void parseData() + { + _center = _mineplexWorld.getSpongeLocation("LOOK_AT"); + + _winnersLocation = _mineplexWorld.getGoldLocation("Lime"); + _losersLocation = _mineplexWorld.getGoldLocation("Red"); + + _winnersLocation.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(_winnersLocation, getSpectatorLocation()))); + _losersLocation.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(_losersLocation, getSpectatorLocation()))); + + List corners = getRedPoints(); + _arenaPaste = corners.get(0); + _arena = UtilSchematic.createSchematic(corners.get(0), corners.get(1)); + _arenaSize = _center.getBlockX() - _arenaPaste.getBlockX(); + + getYellowSpawns().forEach(location -> location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, getSpectatorLocation())))); + } + + @EventHandler + public void updateChallenge(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || !isLive() || _creating || (_challenge != null && _challenge.getLifetime().isActive())) + { + return; + } + + if (_challengeTypes.isEmpty()) + { + setState(GameState.End); + return; + } + + int index = UtilMath.r(_challengeTypes.size()); + ChallengeType challengeType = _challengeTypes.get(index); + _challengeTypes.remove(index); + + if (challengeType == null) + { + setState(GameState.End); + return; + } + + _arena.paste(_arenaPaste, false); + + try + { + _challenge = challengeType.getChallengeClass().getConstructor(Quick.class).newInstance(this); + } + catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) + { + e.printStackTrace(); + setState(GameState.End); + } + + _damageComponent.setPvp(false); + _creating = true; + + if (_delay) + { + getManager().runSyncTimer(new BukkitRunnable() + { + int note = 0; + + @Override + public void run() + { + float pitch = 0; + + switch (note) + { + case 0: + pitch = 1.059F; + break; + case 1: + pitch = 1; + break; + case 2: + pitch = 0.840F; + break; + case 3: + pitch = 0.594F; + break; + case 4: + pitch = 0.561F; + break; + case 5: + pitch = 0.890F; + break; + case 6: + pitch = 1.12F; + break; + case 7: + pitch = 1.414F; + break; + } + + for (Player player : getAllPlayers()) + { + player.getWorld().playSound(player.getLocation(), Sound.NOTE_PIANO, 1, pitch); + } + + if (++note == 8) + { + cancel(); + getManager().runSyncLater(() -> start(), 20); + } + } + }, 0, 4); + } + else + { + _delay = true; + start(); + } + } + + private void start() + { + _challenge.start(); + _damageComponent.setPvp(_challenge.isPvp()); + _creating = false; + } + + public void onOut(Player player, boolean winner) + { + NanoPlayer.clear(getManager(), player); + NanoPlayer.setSpectating(player, true); + player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + + if (winner) + { + player.teleport(_winnersLocation); + } + else + { + player.teleport(_losersLocation); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onOut(PlayerDeathOutEvent event) + { + event.setCancelled(true); + event.setShouldRespawn(true); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void playerJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + + if (!_manager.isSpectator(player)) + { + joinTeam(player, _playersTeam); + } + } + + public Location getCenter() + { + return _center; + } + + public List getRedPoints() + { + return _mineplexWorld.getIronLocations("RED"); + } + + public List getGreenPoints() + { + return _mineplexWorld.getIronLocations("GREEN"); + } + + public List getOrangePoints() + { + return _mineplexWorld.getIronLocations("ORANGE"); + } + + public List getYellowPoints() + { + return _mineplexWorld.getIronLocations("YELLOW"); + } + + public List getYellowSpawns() + { + return _mineplexWorld.getGoldLocations("Yellow"); + } + + public int getArenaSize() + { + return _arenaSize; + } + + public void setChallenges(List challenges) + { + _challengeTypes.clear(); + _challengeTypes.addAll(challenges); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeAvoidTNT.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeAvoidTNT.java new file mode 100644 index 000000000..3d2557099 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeAvoidTNT.java @@ -0,0 +1,54 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.Location; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityExplodeEvent; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeAvoidTNT extends Challenge +{ + + public ChallengeAvoidTNT(Quick game) + { + super(game, ChallengeType.AVOID_TNT); + + _winConditions.setTimeoutWin(true); + } + + @Override + public void challengeSelect() + { + } + + @Override + public void disable() + { + } + + @EventHandler + public void updateTNT(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + Location location = UtilAlg.getRandomLocation(_game.getCenter(), _game.getArenaSize(), 0, _game.getArenaSize()); + TNTPrimed tnt = location.getWorld().spawn(location.add(0, 7, 0), TNTPrimed.class); + tnt.setFuseTicks(40); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void entityExplode(EntityExplodeEvent event) + { + event.blockList().clear(); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeBlockSnake.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeBlockSnake.java new file mode 100644 index 000000000..077ac7b99 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeBlockSnake.java @@ -0,0 +1,125 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeBlockSnake extends Challenge +{ + + private List _blocks; + private Block _last; + + public ChallengeBlockSnake(Quick game) + { + super(game, ChallengeType.BLOCK_SNAKE); + + _timeout = TimeUnit.SECONDS.toMillis(90); + _winConditions.setLastOne(true); + } + + @Override + public void challengeSelect() + { + List corners = _game.getOrangePoints(); + _blocks = UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false); + _last = _game.getCenter().getBlock().getRelative(BlockFace.DOWN); + + PotionEffect effect = new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false); + _players.forEach(player -> player.addPotionEffect(effect)); + } + + @Override + public void disable() + { + } + + @EventHandler + public void updateSnake(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !UtilTime.elapsed(_startTime, 3000)) + { + return; + } + + List possible = new ArrayList<>(UtilBlock.horizontals.size()); + + for (BlockFace face : UtilBlock.horizontals) + { + Block next = _last.getRelative(face); + + if (_blocks.contains(next)) + { + possible.add(next); + } + } + + Block block = UtilAlg.Random(possible); + + if (block == null) + { + block = UtilAlg.Random(_blocks); + + if (block == null) + { + for (Player player : _game.getAlivePlayers()) + { + completePlayer(player, false); + } + return; + } + } + + _blocks.remove(block); + _last = block; + + Location location = block.getLocation(); + + if (event.getTick() % 5 == 0) + { + location.getWorld().playSound(location, Sound.CHICKEN_EGG_POP, 1, 1); + } + + MapUtil.QuickChangeBlockAt(location, Material.STAINED_CLAY, (byte) 4); + + _game.getManager().runSyncLater(() -> + { + if (!isRunning()) + { + return; + } + + MapUtil.QuickChangeBlockAt(location, Material.STAINED_CLAY, (byte) 14); + }, 1); + + _game.getManager().runSyncLater(() -> + { + if (!isRunning()) + { + return; + } + + MapUtil.QuickChangeBlockAt(location, Material.AIR); + }, 40); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCraftItem.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCraftItem.java new file mode 100644 index 000000000..c220f443a --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCraftItem.java @@ -0,0 +1,106 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.Recipe; +import org.bukkit.inventory.ShapedRecipe; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilMath; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeCraftItem extends Challenge +{ + + private final ItemStack _result; + + public ChallengeCraftItem(Quick game) + { + super(game, ChallengeType.CRAFT_ITEM); + + _result = new ItemStack(UtilMath.randomElement(new Material[] + { + Material.IRON_AXE, + Material.IRON_SPADE, + Material.IRON_SWORD, + Material.IRON_PICKAXE, + Material.IRON_BLOCK, + Material.IRON_DOOR, + Material.DIAMOND_BLOCK, + Material.DIAMOND_AXE, + Material.DIAMOND_PICKAXE, + Material.IRON_BOOTS, + Material.IRON_LEGGINGS, + Material.IRON_CHESTPLATE, + Material.BUCKET + })); + _winConditions.setTimeoutAfterFirst(true); + } + + @Override + public void challengeSelect() + { + for (Recipe recipe : Bukkit.getRecipesFor(_result)) + { + if (!(recipe instanceof ShapedRecipe)) + { + return; + } + + ShapedRecipe shapedRecipe = (ShapedRecipe) recipe; + + shapedRecipe.getIngredientMap().forEach((character, itemStack) -> + { + if (itemStack == null) + { + return; + } + + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + } + }); + } + + for (Player player : _players) + { + PlayerInventory inventory = player.getInventory(); + + for (int i = 9; i < inventory.getSize(); i++) + { + inventory.setItem(i, _result); + } + } + + _game.getGreenPoints().forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.WORKBENCH)); + } + + @Override + public void disable() + { + } + + @EventHandler + public void craftItem(CraftItemEvent event) + { + Player player = (Player) event.getWhoClicked(); + ItemStack result = event.getInventory().getResult(); + + if (result != null && result.getType().equals(_result.getType())) + { + completePlayer(player, false); + } + else + { + failPlayer(player, false); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCrouch.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCrouch.java new file mode 100644 index 000000000..77abc6d12 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeCrouch.java @@ -0,0 +1,38 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerToggleSneakEvent; + +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeCrouch extends Challenge +{ + + public ChallengeCrouch(Quick game) + { + super(game, ChallengeType.CROUCH); + + _timeout = 1200; + } + + @Override + public void challengeSelect() + { + } + + @Override + public void disable() + { + } + + @EventHandler + public void playerSneak(PlayerToggleSneakEvent event) + { + if (event.isSneaking()) + { + completePlayer(event.getPlayer(), false); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeEnchantItem.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeEnchantItem.java new file mode 100644 index 000000000..b299c34f4 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeEnchantItem.java @@ -0,0 +1,81 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.enchantment.EnchantItemEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class ChallengeEnchantItem extends Challenge +{ + + public ChallengeEnchantItem(Quick game) + { + super(game, ChallengeType.ENCHANT_ITEM); + + _pvp = true; + } + + @Override + public void challengeSelect() + { + ItemStack[] itemStacks = + { + new ItemStack(Material.STONE_SWORD), + new ItemStack(Material.EXP_BOTTLE, 64), + new ItemStack(Material.EYE_OF_ENDER), + new ItemStack(Material.SPECKLED_MELON), + new ItemStack(Material.COOKED_BEEF), + new ItemStack(Material.WOOD, 32), + new ItemStack(Material.MELON_BLOCK), + new ItemStack(Material.COOKED_BEEF, 2) + }; + + UtilAlg.shuffle(itemStacks); + + for (Player player : _players) + { + player.getInventory().addItem(itemStacks); + } + + _game.getGreenPoints().forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.ENCHANTMENT_TABLE)); + } + + @Override + public void disable() + { + } + + @EventHandler + public void enchant(EnchantItemEvent event) + { + completePlayer(event.getEnchanter(), false); + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(), damager = event.GetDamagerPlayer(false); + + if (damagee == null || damager == null) + { + return; + } + + ItemStack itemStack = damager.getItemInHand(); + + if (itemStack != null && itemStack.getItemMeta().hasEnchants()) + { + return; + } + + event.SetCancelled("Non-Enchanted Weapon"); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeFood.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeFood.java new file mode 100644 index 000000000..8f9b86300 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeFood.java @@ -0,0 +1,71 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeFood extends Challenge +{ + + public ChallengeFood(Quick game) + { + super(game, ChallengeType.FOOD); + } + + @Override + public void challengeSelect() + { + ItemStack[] itemStacks = + { + new ItemStack(Material.COOKED_BEEF), + new ItemStack(Material.COOKED_CHICKEN), + new ItemStack(Material.COOKED_FISH), + new ItemStack(Material.GOLDEN_APPLE), + new ItemStack(Material.RAW_CHICKEN), + new ItemStack(Material.SPIDER_EYE), + new ItemStack(Material.APPLE), + new ItemStack(Material.RAW_FISH), + }; + UtilAlg.shuffle(itemStacks); + + for (Player player : _players) + { + player.getInventory().addItem(itemStacks); + player.setFoodLevel(2); + } + + _timeout = TimeUnit.SECONDS.toMillis(8); + } + + @Override + public void disable() + { + } + + @EventHandler + public void updateComplete(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + for (Player player : _game.getAlivePlayers()) + { + if (player.getFoodLevel() == 20) + { + completePlayer(player, true); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIgniteTNT.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIgniteTNT.java new file mode 100644 index 000000000..d98ae803b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIgniteTNT.java @@ -0,0 +1,88 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeIgniteTNT extends Challenge +{ + + public ChallengeIgniteTNT(Quick game) + { + super(game, ChallengeType.IGNITE_TNT); + } + + @Override + public void challengeSelect() + { + List corners = _game.getOrangePoints(); + List blocks = UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false); + int max = Math.min(20, _players.size() / 2); + + for (int i = 0; i < max; i++) + { + Block block = UtilAlg.Random(blocks); + + if (block == null) + { + return; + } + + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.TNT); + } + + ItemStack itemStack = new ItemStack(Material.FLINT_AND_STEEL); + + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + player.setGameMode(GameMode.SURVIVAL); + } + } + + @Override + public void disable() + { + + } + + @EventHandler + public void playerInteract(PlayerInteractEvent event) + { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) + { + return; + } + + Player player = event.getPlayer(); + + if (!isParticipating(player)) + { + return; + } + + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null || itemStack.getType() != Material.FLINT_AND_STEEL || event.getClickedBlock().getType() != Material.TNT) + { + return; + } + + _game.getManager().runSyncLater(() -> completePlayer(player, true), 0); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIntoVoid.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIntoVoid.java new file mode 100644 index 000000000..59df00dd4 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeIntoVoid.java @@ -0,0 +1,43 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class ChallengeIntoVoid extends Challenge +{ + + public ChallengeIntoVoid(Quick game) + { + super(game, ChallengeType.INTO_VOID); + + _winConditions.setTimeoutAfterFirst(true); + } + + @Override + public void challengeSelect() + { + } + + @Override + public void disable() + { + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(); + + if (damagee != null) + { + event.SetCancelled("Into Void"); + completePlayer(damagee, true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePlatform.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePlatform.java new file mode 100644 index 000000000..f50c5673b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePlatform.java @@ -0,0 +1,52 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengePlatform extends Challenge +{ + + public ChallengePlatform(Quick game) + { + super(game, ChallengeType.PLATFORM); + + _timeout = TimeUnit.SECONDS.toMillis(10); + _winConditions.setTimeoutWin(true); + } + + @Override + public void challengeSelect() + { + int size = _game.getArenaSize() - 3; + Location center = UtilAlg.getRandomLocation(_game.getCenter(), size, 0, size); + + size = 2; + + for (Block block : UtilBlock.getInBoundingBox(center.clone().add(size, 0, size), center.clone().subtract(size, 0, size), false)) + { + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.STAINED_CLAY, (byte) 14); + } + + _game.getManager().runSyncLater(() -> + { + List corners = _game.getOrangePoints(); + UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false).forEach(block -> MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR)); + }, 5 * 20); + } + + @Override + public void disable() + { + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePole.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePole.java new file mode 100644 index 000000000..d7f4844a0 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePole.java @@ -0,0 +1,67 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengePole extends Challenge +{ + + private static final int GOAL = 10; + + private int _goalY; + + public ChallengePole(Quick game) + { + super(game, ChallengeType.POLE); + + _timeout = TimeUnit.SECONDS.toMillis(25); + _winConditions.setTimeoutAfterFirst(true); + } + + @Override + public void challengeSelect() + { + _goalY = _game.getCenter().getBlockY() + GOAL; + + ItemStack itemStack = new ItemStack(Material.COBBLESTONE, 64); + + for (Player player : _players) + { + player.setGameMode(GameMode.SURVIVAL); + player.getInventory().addItem(itemStack); + } + } + + @Override + public void disable() + { + } + + @EventHandler + public void blockPlace(BlockPlaceEvent event) + { + Player player = event.getPlayer(); + + if (!isParticipating(player) || !inArena(event.getBlock())) + { + return; + } + + event.setCancelled(false); + + if (player.getLocation().getY() > _goalY) + { + completePlayer(player, true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePunchAPig.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePunchAPig.java new file mode 100644 index 000000000..ffe8591f5 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengePunchAPig.java @@ -0,0 +1,105 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class ChallengePunchAPig extends Challenge +{ + + private final Map _punched; + + public ChallengePunchAPig(Quick game) + { + super(game, ChallengeType.PUNCH_A_PIG); + + _punched = new HashMap<>(); + + _timeout = TimeUnit.SECONDS.toMillis(9); + } + + @Override + public void challengeSelect() + { + + } + + @Override + public void disable() + { + _punched.clear(); + } + + @EventHandler + public void updatePigs(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + int max = Math.min(10, _players.size()); + int size = _game.getArenaSize() - 1; + + _game.getWorldComponent().setCreatureAllowOverride(true); + + for (int i = 0; i < max; i++) + { + Location location = UtilAlg.getRandomLocation(_game.getCenter(), size, 0, size); + location.setYaw(UtilMath.r(360)); + + location.getWorld().spawn(location, Pig.class); + } + + _game.getWorldComponent().setCreatureAllowOverride(false); + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + LivingEntity damagee = event.GetDamageeEntity(); + Player damager = event.GetDamagerPlayer(false); + + if (damagee instanceof Pig) + { + int punched = _punched.getOrDefault(damager, 0) + 1; + + if (punched == 5) + { + completePlayer(damager, true); + } + else + { + _punched.put(damager, punched); + UtilTextMiddle.display(null, C.cGreen + punched, 0, 20, 10, damager); + } + + event.AddMod(damager.getName(), 20); + } + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + event.setDroppedExp(0); + event.getDrops().clear(); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeRedBlocks.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeRedBlocks.java new file mode 100644 index 000000000..13ab17a45 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeRedBlocks.java @@ -0,0 +1,124 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeRedBlocks extends Challenge +{ + + private List _blocks; + + public ChallengeRedBlocks(Quick game) + { + super(game, ChallengeType.RED_BLOCKS); + + _timeout = TimeUnit.MINUTES.toMillis(2); + _winConditions.setLastOne(true); + } + + @Override + public void challengeSelect() + { + List corners = _game.getOrangePoints(); + + _blocks = UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false); + _blocks.forEach(block -> MapUtil.QuickChangeBlockAt(block.getLocation(), Material.WOOL)); + } + + @Override + public void disable() + { + _blocks.clear(); + } + + @EventHandler + public void updateFloor(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !UtilTime.elapsed(_startTime, 1000)) + { + return; + } + + for (int i = 0; i < 4; i++) + { + Block block = UtilAlg.Random(_blocks); + + if (block == null) + { + return; + } + + tickBlock(block); + } + } + + @EventHandler + public void updatePlayers(UpdateEvent event) + { + if (event.getType() != UpdateType.TWOSEC) + { + return; + } + + for (Player player : _players) + { + Pair box = UtilEnt.getSideStandingBox(player); + Location min = box.getLeft(), max = box.getRight(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) + { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) + { + tickBlock(player.getLocation().subtract(x, 0.5, z).getBlock()); + } + } + } + } + + private void tickBlock(Block block) + { + if (block.getType() == Material.AIR) + { + return; + } + + byte newData = 0; + + switch (block.getData()) + { + case 0: + newData = 4; + break; + case 4: + newData = 1; + break; + case 1: + newData = 14; + break; + case 14: + _blocks.remove(block); + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR); + return; + } + + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.WOOL, newData); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSlimeJump.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSlimeJump.java new file mode 100644 index 000000000..45c0d3a74 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSlimeJump.java @@ -0,0 +1,85 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeSlimeJump extends Challenge +{ + + public ChallengeSlimeJump(Quick game) + { + super(game, ChallengeType.SLIME_JUMP); + + _pvp = true; + } + + @Override + public void challengeSelect() + { + List corners = _game.getOrangePoints(); + UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false).forEach(block -> + { + Location location = block.getLocation(); + + MapUtil.QuickChangeBlockAt(location, Material.SLIME_BLOCK); + MapUtil.QuickChangeBlockAt(location.clone().add(0, 12, 0), Material.BARRIER); + + if (Math.random() < 0.1) + { + MapUtil.QuickChangeBlockAt(location.clone().add(0, 7, 0), Material.EMERALD_BLOCK); + } + }); + + ItemStack itemStack = new ItemStack(Material.STICK); + PotionEffect jump = new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 7, false, false); + + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + player.addPotionEffect(jump); + } + } + + @Override + public void disable() + { + } + + @Override + protected void completeRemaining() + { + for (Player player : _game.getAlivePlayers()) + { + Pair box = UtilEnt.getSideStandingBox(player); + Location min = box.getLeft(), max = box.getRight(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) + { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) + { + if (player.getLocation().subtract(x, 0.5, z).getBlock().getType() == Material.EMERALD_BLOCK) + { + completePlayer(player, true); + return; + } + } + } + + failPlayer(player, true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpeedBridge.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpeedBridge.java new file mode 100644 index 000000000..ecab6fe2a --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpeedBridge.java @@ -0,0 +1,99 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.event.PlayerGameApplyEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeSpeedBridge extends Challenge +{ + + private int _goalX; + + public ChallengeSpeedBridge(Quick game) + { + super(game, ChallengeType.SPEED_BRIDGE); + + _winConditions.setTimeoutAfterFirst(true); + _timeout = TimeUnit.SECONDS.toMillis(30); + } + + @Override + public void challengeSelect() + { + _goalX = _game.getMineplexWorld().getIronLocation("LIGHT_BLUE").getBlockX(); + + List corners = _game.getYellowPoints(); + + for (Block block : UtilBlock.getInBoundingBox(corners.get(0).clone().subtract(0, 1, 0), corners.get(1).clone().subtract(0, 1, 0))) + { + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR); + } + + ItemStack itemStack = new ItemStack(Material.COBBLESTONE, 64); + + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + player.setGameMode(GameMode.SURVIVAL); + } + } + + @Override + public void disable() + { + } + + @EventHandler + public void playerApply(PlayerGameApplyEvent event) + { + event.setRespawnLocation(UtilAlg.getLocationAwayFromPlayers(_game.getYellowSpawns(), _players)); + } + + @EventHandler + public void blockPlace(BlockPlaceEvent event) + { + Player player = event.getPlayer(); + + if (!isParticipating(player) || !inArena(event.getBlock())) + { + return; + } + + event.setCancelled(false); + } + + @EventHandler + public void updateComplete(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + for (Player player : _game.getAlivePlayers()) + { + if (player.getLocation().getX() <= _goalX) + { + completePlayer(player, true); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpleef.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpleef.java new file mode 100644 index 000000000..7a8ab67ee --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSpleef.java @@ -0,0 +1,82 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Effect; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilBlock; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeSpleef extends Challenge +{ + + public ChallengeSpleef(Quick game) + { + super(game, ChallengeType.SPLEEF); + + _timeout = TimeUnit.MINUTES.toMillis(1); + _winConditions.setLastOne(true); + } + + @Override + public void challengeSelect() + { + ItemStack itemStack = new ItemStack(Material.DIAMOND_SPADE); + + _game.getManager().runSyncLater(() -> + { + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + player.getInventory().setHeldItemSlot(0); + player.setGameMode(GameMode.SURVIVAL); + } + }, 20); + + List corners = _game.getOrangePoints(); + UtilBlock.getInBoundingBox(corners.get(0), corners.get(1), false).forEach(block -> MapUtil.QuickChangeBlockAt(block.getLocation(), Material.SNOW_BLOCK)); + } + + @Override + public void disable() + { + } + + @EventHandler + public void blockDamage(BlockDamageEvent event) + { + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (!isParticipating(player) || itemStack == null || itemStack.getType() != Material.DIAMOND_SPADE) + { + return; + } + + Block block = event.getBlock(); + + if (block.getType() != Material.SNOW_BLOCK) + { + return; + } + + event.setCancelled(true); + + Location location = block.getLocation(); + + location.getWorld().playEffect(location, Effect.STEP_SOUND, block.getType()); + MapUtil.QuickChangeBlockAt(location, Material.AIR); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeStandStill.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeStandStill.java new file mode 100644 index 000000000..a9e2ce649 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeStandStill.java @@ -0,0 +1,60 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +import mineplex.core.common.util.UtilTime; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeStandStill extends Challenge +{ + + public ChallengeStandStill(Quick game) + { + super(game, ChallengeType.STAND_STILL); + + _timeout = TimeUnit.SECONDS.toMillis(8); + _winConditions.setTimeoutWin(true); + } + + @Override + public void challengeSelect() + { + } + + @Override + public void disable() + { + } + + @EventHandler + public void playerMove(PlayerMoveEvent event) + { + if (!UtilTime.elapsed(_startTime, 1000)) + { + return; + } + + Player player = event.getPlayer(); + + if (!isParticipating(player)) + { + return; + } + + Location from = event.getFrom(), to = event.getTo(); + + if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ()) + { + return; + } + + failPlayer(player, true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSumo.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSumo.java new file mode 100644 index 000000000..f7361b699 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeSumo.java @@ -0,0 +1,92 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class ChallengeSumo extends Challenge +{ + + private final Map _knockback; + + public ChallengeSumo(Quick game) + { + super(game, ChallengeType.SUMO); + + _knockback = new HashMap<>(); + + _timeout = TimeUnit.MINUTES.toMillis(1); + _pvp = true; + _winConditions.setLastOne(true); + } + + @Override + public void challengeSelect() + { + ItemStack itemStack = new ItemBuilder(Material.STICK) + .setTitle(C.cGoldB + "Knockback Stick") + .setGlow(true) + .build(); + + for (Player player : _players) + { + PlayerInventory inventory = player.getInventory(); + + for (int i = 0; i < 9; i++) + { + inventory.setItem(i, itemStack); + } + } + } + + @Override + public void disable() + { + } + + @EventHandler(ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(); + Player damager = event.GetDamagerPlayer(false); + + if (damagee == null || damager == null) + { + return; + } + + UtilPlayer.hunger(damager, 4); + + int knockback = _knockback.getOrDefault(damagee, 4); + _knockback.put(damagee, knockback + 1); + event.AddKnockback("Knockback Stick", knockback); + event.AddMod(_game.getGameType().getName(), -event.GetDamage() + 0.1); + } + + @EventHandler + public void updateHunger(UpdateEvent event) + { + if (event.getType() != UpdateType.TWOSEC) + { + return; + } + + _players.forEach(player -> UtilPlayer.hunger(player, -1)); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeThrowEggs.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeThrowEggs.java new file mode 100644 index 000000000..03af7a77b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeThrowEggs.java @@ -0,0 +1,59 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeThrowEggs extends Challenge +{ + + public ChallengeThrowEggs(Quick game) + { + super(game, ChallengeType.THROW_EGGS); + } + + @Override + public void challengeSelect() + { + ItemStack itemStack = new ItemStack(Material.EGG, 64); + + for (Player player : _players) + { + player.getInventory().addItem(itemStack); + } + } + + @Override + public void disable() + { + } + + @EventHandler + public void updateEggs(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + playerLoop: for (Player player : _game.getAlivePlayers()) + { + for (ItemStack itemStack : player.getInventory().getContents()) + { + if (itemStack != null && itemStack.getType() == Material.EGG) + { + continue playerLoop; + } + } + + completePlayer(player, false); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeZombies.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeZombies.java new file mode 100644 index 000000000..812774ef2 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/quick/challenges/ChallengeZombies.java @@ -0,0 +1,86 @@ +package mineplex.game.nano.game.games.quick.challenges; + +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.disguise.disguises.DisguiseVillager; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.game.games.quick.Challenge; +import mineplex.game.nano.game.games.quick.ChallengeType; +import mineplex.game.nano.game.games.quick.Quick; + +public class ChallengeZombies extends Challenge +{ + + public ChallengeZombies(Quick game) + { + super(game, ChallengeType.ZOMBIES); + + _timeout = TimeUnit.SECONDS.toMillis(25); + _winConditions.setTimeoutWin(true); + } + + @Override + public void challengeSelect() + { + DisguiseManager manager = _game.getManager().getDisguiseManager(); + + for (Player player : _players) + { + DisguiseVillager disguise = new DisguiseVillager(player); + + disguise.setName(_game.getPlayersTeam().getChatColour() + player.getName()); + disguise.setCustomNameVisible(true); + + manager.disguise(disguise); + } + } + + @Override + public void disable() + { + } + + @EventHandler + public void updateZombies(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + Location location = UtilAlg.Random(_game.getGreenPoints()); + + if (location == null) + { + return; + } + + _game.getWorldComponent().setCreatureAllowOverride(true); + + location.setYaw(UtilMath.r(360)); + + Zombie zombie = location.getWorld().spawn(location, Zombie.class); + zombie.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false, false)); + zombie.setTarget(UtilAlg.Random(_players)); + + _game.getWorldComponent().setCreatureAllowOverride(false); + } + + @EventHandler + public void entityCombust(EntityCombustEvent event) + { + event.setCancelled(true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/redgreenlight/RedGreenLight.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/redgreenlight/RedGreenLight.java new file mode 100644 index 000000000..5826fd7d4 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/redgreenlight/RedGreenLight.java @@ -0,0 +1,302 @@ +package mineplex.game.nano.game.games.redgreenlight; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GamePlacements; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.GameStateChangeEvent; + +public class RedGreenLight extends SoloGame +{ + + enum LightState + { + + GREEN("GO", ChatColor.GREEN, (byte) 5, Sound.FIREWORK_LAUNCH), + YELLOW("SLOW", ChatColor.YELLOW, (byte) 4, Sound.NOTE_STICKS), + RED("STOP", ChatColor.RED, (byte) 14, Sound.NOTE_BASS_DRUM); + + final String Title; + final byte BlockData; + final ItemStack WoolItem; + final Sound SoundToPlay; + + LightState(String name, ChatColor colour, byte blockData, Sound soundToPlay) + { + Title = colour + C.Bold + name; + BlockData = blockData; + WoolItem = new ItemBuilder(Material.WOOL, blockData) + .setTitle(Title) + .build(); + SoundToPlay = soundToPlay; + } + } + + private final List _order; + + private List _wall, _lights; + private Location _villager; + private int _zGoal; + + private boolean _scheduled; + private LightState _state; + + public RedGreenLight(NanoManager manager) + { + super(manager, GameType.RED_GREEN_LIGHT, new String[] + { + "Two Rules", + C.cGreenB + "Run" + C.Reset + " on " + C.cGreenB + "Green", + C.cRedB + "STOP" + C.Reset + " on " + C.cRedB + "RED", + C.cYellow + "First Player" + C.Reset + " to the villager wins!" + }); + + _order = new ArrayList<>(); + + _teamComponent.setAdjustSpawnYaw(false); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setDamage(false); + + _endComponent.setTimeout(TimeUnit.MINUTES.toMillis(3)); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Players"); + + for (Player other : _order.subList(0, Math.min(12, _order.size()))) + { + scoreboard.write((other.equals(player) ? C.cGreen : "") + other.getName()); + } + + scoreboard.writeNewLine(); + + scoreboard.draw(); + }); + } + + @Override + protected void parseData() + { + _wall = _mineplexWorld.getSpongeLocations(String.valueOf(Material.EMERALD_ORE.getId())); + _lights = _mineplexWorld.getSpongeLocations(String.valueOf(Material.DIAMOND_ORE.getId())); + _villager = _mineplexWorld.getIronLocation("LIME"); + _zGoal = _villager.getBlockZ() - 3; + + _wall.forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.STAINED_GLASS_PANE, (byte) 15)); + setLights(LightState.GREEN); + } + + @Override + public boolean endGame() + { + if (super.endGame() || _order.isEmpty()) + { + return true; + } + + _order.sort((o1, o2) -> Double.compare(o2.getLocation().getZ(), o1.getLocation().getZ())); + + if (!_order.isEmpty()) + { + Player top = _order.get(0); + + return top.getLocation().getZ() > _zGoal; + } + + return false; + } + + @Override + protected GamePlacements createPlacements() + { + return GamePlacements.fromTeamPlacements(_order); + } + + @Override + public void disable() + { + _wall.clear(); + _lights.clear(); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + _order.addAll(getAlivePlayers()); + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.getState() != GameState.Live) + { + return; + } + + _wall.forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.AIR)); + + _worldComponent.setCreatureAllowOverride(true); + + _villager.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(_villager, getSpectatorLocation()))); + + Villager villager = _villager.getWorld().spawn(_villager, Villager.class); + + UtilEnt.vegetate(villager, true); + UtilEnt.ghost(villager, true, false); + UtilEnt.setFakeHead(villager, true); + + villager.setCustomName(C.cGreen + "Danger Dan"); + villager.setCustomNameVisible(true); + + _worldComponent.setCreatureAllowOverride(false); + } + + @EventHandler + public void updateLights(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER || !isLive()) + { + return; + } + + if (endGame()) + { + setState(GameState.End); + } + + if (_scheduled) + { + return; + } + + _scheduled = true; + + // 2 - 4 seconds + int ticksToRun = UtilMath.rRange(40, 80); + // 1 - 1.5 seconds + int ticksToSlow = UtilMath.rRange(20, 30); + // 1 - 2 seconds + int ticksToStop = UtilMath.rRange(20, 40); + + setLights(LightState.GREEN); + + getManager().runSyncLater(() -> + { + setLights(LightState.YELLOW); + + getManager().runSyncLater(() -> + { + setLights(LightState.RED); + + getManager().runSyncLater(() -> _scheduled = false, ticksToStop); + }, ticksToSlow); + }, ticksToRun); + } + + @EventHandler + public void playerMove(PlayerMoveEvent event) + { + if (!isLive() || _state != LightState.RED) + { + return; + } + + Player player = event.getPlayer(); + + if (UtilPlayer.isSpectator(player)) + { + return; + } + + Location from = event.getFrom(), to = event.getTo(); + + if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() || !Recharge.Instance.use(player, "Caught", 1000, false, false)) + { + return; + } + + player.teleport(_playersTeam.getSpawn()); + player.playSound(player.getLocation(), Sound.ENDERMAN_TELEPORT, 1, 1); + UtilTextMiddle.display(null, C.cRed + "You Moved!", 0, 30, 10, player); + } + + private void setLights(LightState state) + { + if (state == LightState.RED) + { + getManager().runSyncLater(() -> _state = state, 7); + } + else + { + _state = state; + } + + _lights.forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.WOOL, state.BlockData)); + + if (!isLive()) + { + return; + } + + Player[] players = getAlivePlayers().toArray(new Player[0]); + + for (Player player : players) + { + PlayerInventory inventory = player.getInventory(); + + for (int i = 0; i < 9; i++) + { + inventory.setItem(i, state.WoolItem); + } + + player.playSound(player.getLocation(), state.SoundToPlay, 1, 0.8F); + } + + UtilTextMiddle.display(null, state.Title, 5, 10, 5, players); + } + + @EventHandler + public void playerInteractEntity(PlayerInteractEntityEvent event) + { + if (event.getRightClicked() instanceof Villager) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeBike.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeBike.java new file mode 100644 index 000000000..6f102eb9b --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeBike.java @@ -0,0 +1,155 @@ +package mineplex.game.nano.game.games.slimecycles; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; + +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilTime; + +public class SlimeBike +{ + + private static final long DIRECTION_RATE = 500; + private static final double DELTA_TICK = 0.4; + + private final SlimeCycles _game; + private final Player _host; + private final byte _colour; + private final Slime _bike; + private final List _trail; + + private Block _lastBlock; + private float _lastYaw; + private long _lastChange; + private boolean _changeDirection; + + SlimeBike(SlimeCycles game, Player host, DyeColor colour) + { + _game = game; + _host = host; + _colour = colour.getWoolData(); + _bike = host.getWorld().spawn(host.getLocation(), Slime.class); + _trail = new ArrayList<>(); + + _bike.setSize(2); + UtilEnt.vegetate(_bike, true); + UtilEnt.ghost(_bike, true, false); + UtilEnt.setFakeHead(_bike, true); + + _lastBlock = _bike.getLocation().getBlock(); + _lastYaw = -1; + } + + void updateDirection() + { + if (UtilTime.elapsed(_lastChange, DIRECTION_RATE)) + { + float yaw = (Math.round(_host.getLocation().getYaw() / 90F) & 0x3) * 90F; + + if (_lastYaw != yaw) + { + _lastYaw = yaw; + _lastChange = System.currentTimeMillis(); + _changeDirection = true; + } + } + } + + boolean updateLocation() + { + Location location = _bike.getLocation(); + Block block = location.getBlock(); + + if (block.getType() != Material.AIR) + { + return true; + } + + double x = location.getX(); + double z = location.getZ(); + double deltaX = 0; + double deltaZ = 0; + + if (_lastYaw == 0) + { + deltaZ += DELTA_TICK; + } + else if (_lastYaw == 90) + { + deltaX -= DELTA_TICK; + } + else if (_lastYaw == 180) + { + deltaZ -= DELTA_TICK; + } + else + { + deltaX += DELTA_TICK; + } + + if (!block.equals(_lastBlock)) + { + if (_trail.size() >= _game.getTrailSize()) + { + Location remove = _trail.remove(0); + + MapUtil.QuickChangeBlockAt(remove, Material.AIR); + } + + Location lastBlock = _lastBlock.getLocation(); + + _trail.add(lastBlock); + MapUtil.QuickChangeBlockAt(lastBlock, Material.STAINED_GLASS_PANE, _colour); + + _lastBlock = block; + } + + if (_changeDirection) + { + boolean canChange = false; + + if (deltaZ != 0 && x - location.getBlockX() > 0.5) + { + x = location.getBlockX() + 0.5; + canChange = true; + } + else if (deltaX != 0 && z - location.getBlockZ() > 0.5) + { + z = location.getBlockZ() + 0.5; + canChange = true; + } + + if (canChange) + { + _changeDirection = false; + UtilEnt.CreatureLook(_bike, _lastYaw); + } + } + + location.setX(x + deltaX); + location.setZ(z + deltaZ); + + UtilEnt.setPosition(_bike, location); + return false; + } + + void clean() + { + _bike.remove(); + _trail.forEach(location -> MapUtil.QuickChangeBlockAt(location, Material.AIR)); + _trail.clear(); + } + + public Slime getEntity() + { + return _bike; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeCycles.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeCycles.java new file mode 100644 index 000000000..5b7e4bffa --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/slimecycles/SlimeCycles.java @@ -0,0 +1,162 @@ +package mineplex.game.nano.game.games.slimecycles; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.components.player.NightVisionComponent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class SlimeCycles extends SoloGame +{ + + private final DyeColor[] _colours = + { + DyeColor.RED, + DyeColor.LIME, + DyeColor.LIGHT_BLUE, + DyeColor.PURPLE, + DyeColor.ORANGE, + DyeColor.YELLOW, + DyeColor.BLUE, + DyeColor.PINK, + DyeColor.CYAN, + DyeColor.WHITE + }; + private int _colourIndex; + + private final Map _bikes; + private int _trailSize; + + public SlimeCycles(NanoManager manager) + { + super(manager, GameType.SLIME_CYCLES, new String[] + { + "Control your " + C.cGreen + "Slime" + C.Reset + " by looking.", + C.cRed + "Avoid" + C.Reset + " other trails and walls.", + C.cYellow + "Last player" + C.Reset + " standing wins!", + }); + + _bikes = new HashMap<>(); + _trailSize = 10; + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + _teamComponent.setRespawnRechargeTime(TimeUnit.SECONDS.toMillis(12)); + + _endComponent.setTimeout(TimeUnit.MINUTES.toMillis(3)); + + new NightVisionComponent(this); + } + + @Override + protected void parseData() + { + _mineplexWorld.getWorld().setTime(18000); + } + + @Override + public void disable() + { + _bikes.clear(); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + getManager().runSyncLater(() -> + { + _worldComponent.setCreatureAllowOverride(true); + _bikes.put(player, new SlimeBike(this, player, _colours[_colourIndex])); + _worldComponent.setCreatureAllowOverride(false); + + _colourIndex = (_colourIndex + 1) % _colours.length; + }, 1); + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + if (event.GetDamageeEntity() instanceof Slime) + { + event.SetCancelled("Bike Damage"); + } + } + + @EventHandler + public void updateBikes(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !inProgress()) + { + return; + } + + _bikes.entrySet().removeIf(entry -> + { + Player player = entry.getKey(); + SlimeBike bike = entry.getValue(); + + if (!player.equals(bike.getEntity().getPassenger())) + { + bike.getEntity().setPassenger(player); + } + + if (!isLive()) + { + return false; + } + + bike.updateDirection(); + + if (bike.updateLocation() && !hasRespawned(player)) + { + Location location = player.getLocation(); + + player.getWorld().playSound(location, Sound.EXPLODE, 1, 1); + UtilParticle.PlayParticleToAll(ParticleType.HUGE_EXPLOSION, location, null, 0, 1, ViewDist.LONG); + bike.clean(); + getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 500, false, true, true, getGameType().getName(), "Vaporisation"); + return true; + } + + return false; + }); + } + + @EventHandler + public void updateTrailSize(UpdateEvent event) + { + if (event.getType() != UpdateType.TWOSEC || !isLive()) + { + return; + } + + _trailSize++; + } + + int getTrailSize() + { + return _trailSize; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/spleef/Spleef.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/spleef/Spleef.java new file mode 100644 index 000000000..2104b137e --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/spleef/Spleef.java @@ -0,0 +1,207 @@ +package mineplex.game.nano.game.games.spleef; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.C; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; + +public class Spleef extends SoloGame +{ + + private static final long BLOCK_DECAY = 1800; + + private final Map _blocks = new HashMap<>(); + + public Spleef(NanoManager manager) + { + super(manager, GameType.SPLEEF, new String[] + { + C.cGreen + "Punch Blocks" + C.Reset + " to break them!", + C.cRed + "Blocks Fall" + C.Reset + " from underneath you.", + C.cYellow + "Last Player" + C.Reset + " alive wins!" + }); + + _prepareComponent.setPrepareFreeze(false); + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + _worldComponent.setBlockBreak(true); + + _waterComponent.override(); + } + + @Override + protected void parseData() + { + + } + + @Override + public void disable() + { + + } + + @EventHandler + public void snowballHit(ProjectileHitEvent event) + { + Projectile projectile = event.getEntity(); + + if (!isLive() || !(projectile instanceof Snowball) || !(projectile.getShooter() instanceof Player)) + { + return; + } + + Location location = projectile.getLocation().add(projectile.getVelocity().multiply(0.8)); + Block block = location.getBlock(); + + if (block.getType() == Material.AIR) + { + Block closest = null; + double closestDist = Double.MAX_VALUE; + + for (Block other : UtilBlock.getSurrounding(block, true)) + { + if (other.getType() == Material.AIR) + { + continue; + } + + double dist = UtilMath.offsetSquared(location, other.getLocation().add(0.5, 0.5, 0.5)); + + if (closest == null || dist < closestDist) + { + closest = other; + closestDist = dist; + } + } + + if (closest != null) + { + block = closest; + } + } + + blockFade(block, (Player) projectile.getShooter()); + } + + @EventHandler(priority = EventPriority.LOW) + public void blockHit(BlockDamageEvent event) + { + Player player = event.getPlayer(); + + if (!isLive() || UtilPlayer.isSpectator(player)) + { + return; + } + + Block block = event.getBlock(); + event.setCancelled(true); + + if (block.getType() == Material.BEDROCK) + { + return; + } + + blockFade(block, player); + + if (!player.getInventory().contains(Material.SNOW_BALL, 16)) + { + player.getInventory().addItem(new ItemStack(Material.SNOW_BALL)); + } + } + + private void blockFade(Block block, Player player) + { + if (block.getType() == Material.BEDROCK || block.getType() == Material.LAVA || block.getType() == Material.STATIONARY_LAVA) + { + return; + } + + UtilPlayer.hunger(player, 1); + block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR); + } + + @EventHandler + public void updateRunner(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + for (Player player : getAlivePlayers()) + { + Pair box = UtilEnt.getSideStandingBox(player); + Location min = box.getLeft(), max = box.getRight(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) + { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) + { + addBlock(player.getLocation().add(x, -0.5, z).getBlock()); + } + } + } + + _blocks.entrySet().removeIf(entry -> + { + Block block = entry.getKey(); + long time = entry.getValue(); + + if (!UtilTime.elapsed(time, BLOCK_DECAY)) + { + return false; + } + + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.AIR); + return true; + }); + } + + private void addBlock(Block block) + { + if (block == null || block.getType() == Material.AIR || block.getType() == Material.BEDROCK || block.isLiquid() || block.getRelative(BlockFace.UP).getType() != Material.AIR || _blocks.containsKey(block)) + { + return; + } + + _blocks.put(block, System.currentTimeMillis()); + MapUtil.QuickChangeBlockAt(block.getLocation(), Material.STAINED_CLAY, (byte) 14); + } + + @EventHandler + public void blockForm(EntityChangeBlockEvent event) + { + event.setCancelled(true); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/sploor/Sploor.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/sploor/Sploor.java new file mode 100644 index 000000000..e1feb03c2 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/sploor/Sploor.java @@ -0,0 +1,484 @@ +package mineplex.game.nano.game.games.sploor; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import com.mineplex.anticheat.checks.move.Glide; +import com.mineplex.anticheat.checks.move.HeadRoll; +import com.mineplex.anticheat.checks.move.Speed; + +import mineplex.core.Managers; +import mineplex.core.antihack.AntiHack; +import mineplex.core.common.util.C; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.disguise.disguises.DisguiseBase; +import mineplex.core.disguise.disguises.DisguiseSquid; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.TeamGame; +import mineplex.game.nano.game.components.team.GameTeam; +import mineplex.game.nano.game.event.GameTimeoutEvent; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; +import mineplex.game.nano.game.games.microbattle.components.TeamArmourComponent; +import mineplex.minecraft.game.core.combat.DeathMessageType; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public class Sploor extends TeamGame +{ + + private static final Material GUN_MATERIAL = Material.DIAMOND_BARDING; + private static final String SQUID_MODE_KEY = "Squid Mode"; + + private final Map _balls; + private final Map> _paintedBlocks; + private final Set _squidMode; + + private final ChatColor[] _colours = + { + ChatColor.RED, + ChatColor.GOLD, + ChatColor.YELLOW, + ChatColor.GREEN, + ChatColor.AQUA, + ChatColor.DARK_AQUA, + ChatColor.BLUE, + ChatColor.DARK_PURPLE, + ChatColor.LIGHT_PURPLE, + ChatColor.WHITE + }; + private int _colourIndex; + + public Sploor(NanoManager manager) + { + super(manager, GameType.SPLOOR, new String[] + { + C.cYellow + "Right-Click" + C.Reset + " your " + C.cYellow + "Paint Gun" + C.Reset + " to shoot!", + C.cGreen + "Switch Slots" + C.Reset + " to activate " + C.cPurple + "Squid Mode" + C.Reset + "!", + "In " + C.cYellow + "Squid Mode" + C.Reset + " you can go up " + C.cGreen + "Walls" + C.Reset + "!", + "The team with the most " + C.cPurple + "Painted" + C.Reset + " blocks wins!" + }); + + _balls = new HashMap<>(); + _paintedBlocks = new HashMap<>(); + _squidMode = new HashSet<>(); + + _damageComponent.setFall(false); + + _spectatorComponent.setDeathOut(false); + + _playerComponent.setRegainHealth(false); + + _endComponent.setTimeout(TimeUnit.MINUTES.toMillis(2)); + + new TeamArmourComponent(this); + + AntiHack antiHack = Managers.get(AntiHack.class); + antiHack.addIgnoredCheck(Speed.class); + antiHack.addIgnoredCheck(Glide.class); + antiHack.addIgnoredCheck(HeadRoll.class); + + _scoreboardComponent.setSidebar((player, scoreboard) -> + { + scoreboard.writeNewLine(); + + getTeams().forEach(team -> + { + scoreboard.write(team.getChatColour() + C.Bold + team.getName()); + scoreboard.write(_paintedBlocks.get(team).size() + " Blocks"); + + scoreboard.writeNewLine(); + }); + + scoreboard.draw(); + }); + } + + @Override + protected void createTeams() + { + addTeam(new GameTeam(this, "Red", ChatColor.RED, Color.RED, DyeColor.RED, _mineplexWorld)); + addTeam(new GameTeam(this, "Blue", ChatColor.AQUA, Color.AQUA, DyeColor.LIGHT_BLUE, _mineplexWorld)); + } + + @Override + public GameTeam addTeam(GameTeam gameTeam) + { + _paintedBlocks.put(gameTeam, new HashSet<>()); + + return super.addTeam(gameTeam); + } + + @Override + protected void parseData() + { + + } + + @Override + public void disable() + { + _balls.clear(); + _paintedBlocks.clear(); + } + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + event.SetBroadcastType(DeathMessageType.Simple); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + + player.getInventory().setItem(0, new ItemBuilder(GUN_MATERIAL) + .setTitle(event.getTeam().getChatColour() + C.Bold + "Paint Brush") + .build()); + player.getInventory().setHeldItemSlot(0); + } + + @EventHandler + public void playerInteract(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R) || !isLive()) + { + return; + } + + Player player = event.getPlayer(); + GameTeam team = getTeam(player); + ItemStack itemStack = player.getItemInHand(); + + if (team == null || itemStack == null || itemStack.getType() != GUN_MATERIAL || !Recharge.Instance.use(player, "Shoot Gun", 150, false, false)) + { + return; + } + + Snowball snowball = player.launchProjectile(Snowball.class); + _balls.put(snowball, team); + player.getWorld().playSound(player.getLocation(), Sound.CHICKEN_EGG_POP, 0.5F, 1); + } + + @EventHandler + public void projectileHit(ProjectileHitEvent event) + { + GameTeam team = _balls.remove(event.getEntity()); + + if (team == null) + { + return; + } + + paint(event.getEntity().getLocation(), team, 3); + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void damage(CustomDamageEvent event) + { + if (event.GetProjectile() == null) + { + event.SetCancelled("No Projectile"); + return; + } + + Player damagee = event.GetDamageePlayer(); + Player damager = event.GetDamagerPlayer(true); + + if (damagee == null || damager == null) + { + return; + } + + GameTeam damagerTeam = getTeam(damager); + + if (damagerTeam == null) + { + return; + } + + damager.playSound(damager.getLocation(), Sound.ORB_PICKUP, 0.5F, 1); + paint(damagee, damagerTeam); + + event.AddMod(damager.getName(), "Painting", -event.GetDamage() + 5, true); + event.SetIgnoreArmor(true); + } + + private void paint(Location location, GameTeam painterTeam, int radius) + { + Set painted = _paintedBlocks.get(painterTeam); + + for (Block block : UtilBlock.getBlocksInRadius(location, radius)) + { + if (block.getType() != Material.STAINED_GLASS && block.getType() != Material.WOOL) + { + continue; + } + + for (GameTeam other : getTeams()) + { + if (other.equals(painterTeam)) + { + continue; + } + + if (block.getData() == other.getWoolData()) + { + _paintedBlocks.get(other).remove(block); + } + } + + painted.add(block); + MapUtil.QuickChangeBlockAt(block.getLocation(), block.getType(), painterTeam.getWoolData()); + } + } + + private void paint(Player painted, GameTeam painterTeam) + { + PlayerInventory inventory = painted.getInventory(); + double health = painted.getHealth(); + + if (health > 15) + { + inventory.setBoots(new ItemBuilder(Material.LEATHER_BOOTS) + .setColor(Color.FUCHSIA) + .build()); + } + else if (health > 10) + { + inventory.setLeggings(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setColor(Color.FUCHSIA) + .build()); + } + else if (health > 5) + { + inventory.setChestplate(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setColor(Color.FUCHSIA) + .build()); + } + else + { + inventory.setHelmet(new ItemBuilder(Material.LEATHER_HELMET) + .setColor(Color.FUCHSIA) + .build()); + + paint(painted.getLocation(), painterTeam, 5); + } + } + + @EventHandler + public void updateSquids(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + for (GameTeam team : getTeams()) + { + for (Player player : team.getAlivePlayers()) + { + ItemStack itemStack = player.getItemInHand(); + boolean wantsTo = itemStack == null || itemStack.getType() != GUN_MATERIAL; + boolean onColour = isOnColour(player, team); + boolean onGround = UtilEnt.isGrounded(player); + boolean squid = _squidMode.contains(player); + boolean canUse = Recharge.Instance.usable(player, SQUID_MODE_KEY); + + if (squid) + { + if (!wantsTo || (onGround && !onColour)) + { + setSquid(player, false); + } + else + { + Location location = player.getLocation(); + Block block = location.getBlock(); + + for (BlockFace face : UtilBlock.horizontals) + { + Block next = block.getRelative(face); + + if (next.getData() != team.getWoolData() || UtilMath.offset2dSquared(next.getLocation().add(0.5, 0, 0.5), location) > 1) + { + continue; + } + + UtilAction.velocity(player, new Vector(0, 0.5, 0)); + break; + } + } + } + else + { + if (wantsTo && onColour && canUse) + { + setSquid(player, true); + } + } + } + } + } + + @EventHandler + public void updateSquidText(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + String squidText = getSquidText(); + + for (GameTeam team : getTeams()) + { + for (Player player : team.getAlivePlayers()) + { + if (_squidMode.contains(player)) + { + UtilTextBottom.display(team.getChatColour() + C.Bold + "YOU'VE GOT " + squidText, player); + } + } + } + + _colourIndex = (_colourIndex + 1) % _colours.length; + } + + private String getSquidText() + { + String text = "SUPER SQUID SPEED"; + StringBuilder builder = new StringBuilder(); + int colourIndex = _colourIndex; + + for (char ch : text.toCharArray()) + { + builder + .append(_colours[colourIndex]) + .append(C.Bold) + .append(ch); + + colourIndex = (colourIndex + 1) % _colours.length; + } + + return builder.toString(); + } + + @EventHandler + public void playerQut(PlayerStateChangeEvent event) + { + if (!event.isAlive()) + { + setSquid(event.getPlayer(), false); + } + } + + private boolean isOnColour(Player player, GameTeam team) + { + Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN); + + for (BlockFace next : UtilBlock.horizontals) + { + if (block.getRelative(next).getData() == team.getWoolData()) + { + return true; + } + } + + return block.getData() == team.getWoolData(); + } + + private void setSquid(Player player, boolean enabled) + { + GameTeam team = getTeam(player); + + if (team == null) + { + return; + } + + if (enabled && _squidMode.add(player)) + { + DisguiseSquid disguise = new DisguiseSquid(player); + + disguise.setName(team.getChatColour() + player.getName()); + disguise.setCustomNameVisible(true); + + getManager().getDisguiseManager().disguise(disguise); + + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2, false, false)); + } + else if (!enabled && _squidMode.remove(player)) + { + DisguiseBase disguise = getManager().getDisguiseManager().getActiveDisguise(player); + + if (disguise != null) + { + getManager().getDisguiseManager().undisguise(disguise); + } + + player.removePotionEffect(PotionEffectType.SPEED); + UtilTextBottom.display("", player); + } + + player.getWorld().playSound(player.getLocation(), Sound.SPLASH, 0.5F, 1); + } + + @EventHandler + public void timeout(GameTimeoutEvent event) + { + GameTeam winner = null; + int winnerBlocks = 0; + + for (Entry> entry : _paintedBlocks.entrySet()) + { + int blocks = entry.getValue().size(); + + if (blocks > winnerBlocks) + { + winner = entry.getKey(); + winnerBlocks = blocks; + } + } + + setWinningTeam(winner); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/HotPotato.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/HotPotato.java new file mode 100644 index 000000000..c35c7368c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/HotPotato.java @@ -0,0 +1,156 @@ +package mineplex.game.nano.game.games.tag; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; + +public class HotPotato extends TagGame +{ + + public HotPotato(NanoManager manager) + { + super(manager, GameType.HOT_POTATO, new String[] + { + "Run away from players with " + C.cRed + "TNT" + C.Reset + "!", + C.cYellow + "Punch players" + C.Reset + " to give them the " + C.cYellow + "Potato" + C.Reset + "!", + "Watch out! Potatoes are " + C.cRed + "Explosive" + C.Reset + ".", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + } + + @Override + protected boolean canTag(boolean damageeHolder, boolean damagerHolder) + { + return !damageeHolder && damagerHolder; + } + + @Override + protected void tagPlayers(Player damagee, Player damager) + { + setTagged(damagee, true, false); + setTagged(damager, false, false); + } + + @Override + protected void onTagged(Player player, boolean tagged, boolean initial) + { + if (tagged) + { + PlayerInventory inventory = player.getInventory(); + ItemStack inHand = new ItemBuilder(Material.POTATO_ITEM) + .setTitle(C.cRedB + "Punch Someone!") + .build(); + + for (int i = 0; i < 9; i++) + { + inventory.setItem(i, inHand); + } + + inventory.setHelmet(new ItemStack(Material.TNT)); + inventory.setChestplate(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setColor(Color.RED) + .build()); + inventory.setLeggings(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setColor(Color.RED) + .build()); + inventory.setBoots(new ItemBuilder(Material.LEATHER_BOOTS) + .setColor(Color.RED) + .build()); + + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false, false)); + + UtilTextMiddle.display(null, C.cRed + "You have the Potato! Hit someone to get rid of it!", 0, initial ? 50 : 20, 10, player); + } + else + { + UtilPlayer.clearInventory(player); + player.removePotionEffect(PotionEffectType.SPEED); + } + } + + @Override + protected void onHolderTick(Player player) + { + List players = new ArrayList<>(player.getWorld().getPlayers()); + players.remove(player); + + UtilParticle.PlayParticle(ParticleType.FLAME, player.getLocation().add(0, 2, 0), null, 0.01F, 1, ViewDist.LONG, players.toArray(new Player[0])); + } + + @Override + protected void onRoundEnd(List holders) + { + int exploded = 0; + FireworkEffect effect = FireworkEffect.builder() + .with(UtilMath.randomElement(Type.values())) + .withColor(Color.RED) + .build(); + + for (Player player : getAlivePlayers()) + { + if (!holders.contains(player)) + { + continue; + } + + Location location = player.getLocation().add(0, 1, 0); + + UtilParticle.PlayParticleToAll(ParticleType.HUGE_EXPLOSION, location, null, 0, 1, ViewDist.LONG); + location.getWorld().playSound(location, Sound.EXPLODE, 1, 0.5F); + + if (exploded++ < 5) + { + for (int i = 0; i < 3; i++) + { + UtilFirework.launchFirework(location, effect, null, i); + } + } + + getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.ENTITY_EXPLOSION, 500, false, true, true, getGameType().getName(), "The Hot Potato"); + getManager().runSyncLater(() -> UtilAction.velocity(player, new Vector(0, 2, 0)), 1); + } + + UtilTextBottom.display(C.cRedB + "BOOM!", UtilServer.getPlayers()); + } + + @Override + protected String getScoreboardTitle() + { + return C.cRedB + "Potatoes"; + } + + @Override + protected String getAnnounceRoundString(int holders) + { + return "A round has started with " + F.count(holders) + " potato" + (holders == 1 ? "" : "es") + "!"; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/ReverseTag.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/ReverseTag.java new file mode 100644 index 000000000..12c44cd16 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/ReverseTag.java @@ -0,0 +1,156 @@ +package mineplex.game.nano.game.games.tag; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; + +public class ReverseTag extends TagGame +{ + + public ReverseTag(NanoManager manager) + { + super(manager, GameType.REVERSE_TAG, new String[] + { + "Try to keep hold of the " + C.cGreen + "Emeralds" + C.Reset + "!", + C.cYellow + "Punch players" + C.Reset + " to take their " + C.cGreen + "Emeralds" + C.Reset + "!", + "If you don't have the " + C.cGreen + "Emeralds" + C.Reset + " when the time is up. You lose!", + C.cYellow + "Last player" + C.Reset + " standing wins!" + }); + } + + @Override + protected boolean canTag(boolean damageeHolder, boolean damagerHolder) + { + return damageeHolder && !damagerHolder; + } + + @Override + protected void tagPlayers(Player damagee, Player damager) + { + setTagged(damager, true, false); + setTagged(damagee, false, false); + } + + @Override + protected void onTagged(Player player, boolean tagged, boolean initial) + { + if (tagged) + { + PlayerInventory inventory = player.getInventory(); + ItemStack inHand = new ItemBuilder(Material.EMERALD) + .setTitle(C.cGreenB + "Keep these. Run!") + .build(); + + for (int i = 0; i < 9; i++) + { + inventory.setItem(i, inHand); + } + + inventory.setHelmet(new ItemStack(Material.EMERALD_BLOCK)); + inventory.setChestplate(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setColor(Color.LIME) + .build()); + inventory.setLeggings(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setColor(Color.LIME) + .build()); + inventory.setBoots(new ItemBuilder(Material.LEATHER_BOOTS) + .setColor(Color.LIME) + .build()); + + player.removePotionEffect(PotionEffectType.SPEED); + + UtilTextMiddle.display(null, C.cGreen + "You have Emeralds! Run!", 0, initial ? 50 : 20, 10, player); + } + else + { + UtilPlayer.clearInventory(player); + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false, false)); + } + } + + @Override + protected void onHolderTick(Player player) + { + List players = new ArrayList<>(player.getWorld().getPlayers()); + players.remove(player); + + UtilParticle.PlayParticle(ParticleType.HAPPY_VILLAGER, player.getLocation().add(0, 2, 0), null, 0.01F, 1, ViewDist.LONG, players.toArray(new Player[0])); + } + + @Override + protected void onRoundEnd(List holders) + { + int exploded = 0; + FireworkEffect effect = FireworkEffect.builder() + .with(UtilMath.randomElement(Type.values())) + .withColor(Color.LIME) + .build(); + + for (Player player : getAlivePlayers()) + { + if (holders.contains(player)) + { + continue; + } + + Location location = player.getLocation().add(0, 1, 0); + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, location, 1, 1, 1, 0, 20, ViewDist.LONG); + location.getWorld().playSound(location, Sound.VILLAGER_DEATH, 1, 0.5F); + + if (exploded++ < 5) + { + for (int i = 0; i < 3; i++) + { + UtilFirework.launchFirework(location, effect, null, i); + } + } + + getManager().getDamageManager().NewDamageEvent(player, null, null, DamageCause.ENTITY_EXPLOSION, 500, false, true, true, getGameType().getName(), "Lack of Emeralds"); + getManager().runSyncLater(() -> UtilAction.velocity(player, new Vector(0, 2, 0)), 1); + } + + UtilTextBottom.display(C.cGreenB + "BOOM!", UtilServer.getPlayers()); + } + + @Override + protected String getScoreboardTitle() + { + return C.cGreenB + "Emerald Holders"; + } + + @Override + protected String getAnnounceRoundString(int holders) + { + return "A round has started with " + F.count(holders) + " player" + (holders == 1 ? "" : "s") + " with emeralds!"; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/TagGame.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/TagGame.java new file mode 100644 index 000000000..33b1565c5 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/tag/TagGame.java @@ -0,0 +1,260 @@ +package mineplex.game.nano.game.games.tag; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerToggleSneakEvent; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextBottom; +import mineplex.core.common.util.UtilTime; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.SoloGame; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +public abstract class TagGame extends SoloGame +{ + + private static final long ROUND_END_TIME = TimeUnit.SECONDS.toMillis(4); + private static final int ROUND_MIN_TIME = 12; + private static final int ROUND_MAX_TIME = 18; + private static final double POTATO_FACTOR = 0.5; + private static final int ROUND_TELEPORT_AMOUNT = 4; + + private final List _holders; + + private List _teleportTo; + private long _lastRoundStart, _lastRoundEnd, _roundTime; + + TagGame(NanoManager manager, GameType gameType, String[] description) + { + super(manager, gameType, description); + + _holders = new ArrayList<>(); + + _damageComponent + .setPvp(false) + .setFall(false); + + _prepareComponent.setPrepareFreeze(false); + + _playerComponent.setHideParticles(true); + + _scoreboardComponent.setSidebar((viewer, scoreboard) -> + { + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Players"); + scoreboard.write(getAlivePlayers().size() + " Alive"); + + if (isLive()) + { + scoreboard.writeNewLine(); + + scoreboard.write(getScoreboardTitle()); + + if (_holders.isEmpty()) + { + scoreboard.write("Next Round in " + UtilTime.MakeStr(_lastRoundEnd + ROUND_END_TIME - System.currentTimeMillis())); + } + else + { + for (Player player : _holders.subList(0, Math.min(9, _holders.size()))) + { + scoreboard.write(player.getName()); + } + } + } + + scoreboard.writeNewLine(); + + scoreboard.draw(); + }); + } + + @Override + protected void parseData() + { + _teleportTo = _mineplexWorld.getIronLocations("GREEN"); + _teleportTo.forEach(location -> location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, getSpectatorLocation())))); + } + + protected abstract boolean canTag(boolean damageeHolder, boolean damagerHolder); + + protected abstract void tagPlayers(Player damagee, Player damager); + + protected abstract void onTagged(Player player, boolean tagged, boolean initial); + + protected abstract void onHolderTick(Player player); + + protected abstract void onRoundEnd(List holders); + + protected abstract String getScoreboardTitle(); + + protected abstract String getAnnounceRoundString(int holders); + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + onTagged(event.getPlayer(), false, false); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !isLive()) + { + return; + } + + // Round over + if (_holders.isEmpty()) + { + if (!UtilTime.elapsed(_lastRoundEnd, ROUND_END_TIME)) + { + return; + } + + List alive = getAlivePlayers(); + + _holders.addAll(alive); + int players = (int) Math.floor(_holders.size() * POTATO_FACTOR); + + if (players == 0) + { + setState(GameState.End); + return; + } + + while (_holders.size() > players) + { + _holders.remove(UtilMath.r(_holders.size())); + } + + announce(F.main(getManager().getName(), getAnnounceRoundString(_holders.size()))); + _lastRoundStart = System.currentTimeMillis(); + _roundTime = TimeUnit.SECONDS.toMillis(UtilMath.rRange(ROUND_MIN_TIME, ROUND_MAX_TIME)); + + for (Player player : _holders) + { + setTagged(player, true, true); + } + + if (alive.size() <= ROUND_TELEPORT_AMOUNT) + { + for (int i = 0; i < alive.size(); i++) + { + alive.get(i).teleport(_teleportTo.get(i)); + } + } + } + // Round in progress + else + { + long diff = System.currentTimeMillis() - _lastRoundStart; + + if (diff > _roundTime) + { + _lastRoundEnd = System.currentTimeMillis(); + onRoundEnd(_holders); + _holders.clear(); + + for (Player player : getAlivePlayers()) + { + onTagged(player, false, false); + } + } + else + { + diff = _roundTime - diff; + + UtilTextBottom.displayProgress("Detonation", (double) diff / _roundTime, (diff < 3000 ? C.cRed : "") + UtilTime.MakeStr(Math.max(0, diff)), UtilServer.getPlayers()); + + _holders.forEach(this::onHolderTick); + } + } + } + + protected void setTagged(Player player, boolean tagged, boolean initial) + { + if (tagged) + { + if (!initial) + { + _holders.add(player); + } + } + else + { + _holders.remove(player); + } + + onTagged(player, tagged, initial); + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + if (!isLive()) + { + return; + } + + Player damagee = event.GetDamageePlayer(), damager = event.GetDamagerPlayer(false); + + if (damagee == null || damager == null || UtilPlayer.isSpectator(damagee) || UtilPlayer.isSpectator(damager) || !canTag(_holders.contains(damagee), _holders.contains(damager))) + { + return; + } + + String name = "Tag Player"; + + if (!Recharge.Instance.usable(damagee, name) || !Recharge.Instance.use(damager, name, 500, false, false)) + { + return; + } + + damagee.playEffect(EntityEffect.HURT); + tagPlayers(damagee, damager); + } + + @EventHandler + public void playerQut(PlayerStateChangeEvent event) + { + if (!event.isAlive()) + { + _holders.remove(event.getPlayer()); + } + } + + @Override + public void disable() + { + _holders.clear(); + } + + @EventHandler + public void sneak(PlayerToggleSneakEvent event) + { + if (event.isSneaking() && isAlive(event.getPlayer())) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/territory/Territory.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/territory/Territory.java new file mode 100644 index 000000000..49cf9c516 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/games/territory/Territory.java @@ -0,0 +1,195 @@ +package mineplex.game.nano.game.games.territory; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.disguise.disguises.DisguiseSlime; +import mineplex.core.recharge.Recharge; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.event.PlayerGameRespawnEvent; + +public class Territory extends ScoredSoloGame +{ + + private static final String RECHARGE_KEY = "Inform Move"; + + private final BlockFace[] _connectingFaces = + { + BlockFace.NORTH, + BlockFace.SOUTH, + BlockFace.EAST, + BlockFace.WEST, + BlockFace.NORTH_EAST, + BlockFace.NORTH_WEST, + BlockFace.SOUTH_EAST, + BlockFace.SOUTH_WEST + }; + private final Map _materials; + private Material _default; + private int _materialIndex; + + public Territory(NanoManager manager) + { + super(manager, GameType.TERRITORY, new String[] + { + C.cYellow + "Walk over" + C.Reset + " a block to claim it!", + "You can only claim blocks that are " + C.cRed + "Next To" + C.Reset + " yours", + "Try to " + C.cGreen + "Cut Off" + C.Reset + " other players.", + C.cYellow + "Most blocks claimed" + C.Reset + " wins!" + }); + + _materials = new HashMap<>(); + _materialIndex = 1; + + _damageComponent.setPvp(false); + _damageComponent.setFall(false); + + _endComponent.setTimeout(TimeUnit.MINUTES.toMillis(1)); + } + + @Override + protected void parseData() + { + Block block = _mineplexWorld.getIronLocation("RED").getBlock().getRelative(BlockFace.DOWN); + + _default = block.getType(); + block.setType(Material.AIR); + } + + @Override + public void disable() + { + _materials.clear(); + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.getPlayer(); + DisguiseSlime disguise = new DisguiseSlime(player); + + disguise.setName(event.getTeam().getChatColour() + player.getName()); + disguise.setCustomNameVisible(true); + + getManager().getDisguiseManager().disguise(disguise); + + Material material = null; + + while (material == null || !UtilBlock.fullSolid(material.getId()) || material.equals(_default)) + { + material = Material.getMaterial(_materialIndex++); + } + + _materials.put(player, material); + + player.getInventory().setItem(8, new ItemStack(material)); + + Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN); + block.setType(material); + + for (BlockFace face : UtilBlock.horizontals) + { + block.getRelative(face).setType(material); + } + + incrementScore(player, 5); + player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 254, false, false)); + } + + @EventHandler + public void playerMove(PlayerMoveEvent event) + { + if (!isLive()) + { + return; + } + + Player player = event.getPlayer(); + + if (UtilPlayer.isSpectator(player)) + { + return; + } + + Location from = event.getFrom(), to = event.getTo(); + + if (to.getY() > from.getY()) + { + if (Recharge.Instance.use(player, RECHARGE_KEY, 500, false, false)) + { + UtilTextMiddle.display(null, C.cRedB + "No Jumping!", 0, 20, 10, player); + } + + event.setTo(from); + return; + } + + if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ()) + { + return; + } + + Material material = _materials.get(player); + + if (material == null) + { + return; + } + + boolean allow = true; + Block toBlock = event.getTo().getBlock().getRelative(BlockFace.DOWN); + + if (toBlock.getType() == _default) + { + for (BlockFace face : _connectingFaces) + { + Block next = toBlock.getRelative(face); + + if (next.getType() == material) + { + toBlock.setType(material); + incrementScore(player, 1); + player.playSound(player.getLocation(), Sound.CHICKEN_EGG_POP, 1, 1); + return; + } + } + + allow = false; + } + else if (toBlock.getType() != material) + { + allow = false; + } + + if (!allow) + { + event.setTo(event.getFrom()); + + if (Recharge.Instance.use(player, RECHARGE_KEY, 500, false, false)) + { + UtilTextMiddle.display(null, C.cRed + "You can only claim blocks next to your own!", 0, 20, 10, player); + player.sendMessage(F.main(getManager().getName(), "You can only claim blocks that are next to yours!")); + } + } + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/Room.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/Room.java new file mode 100644 index 000000000..d03b7d0fc --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/Room.java @@ -0,0 +1,36 @@ +package mineplex.game.nano.game.roomed; + +import java.util.Map; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class Room +{ + + private final Player _player; + private final Location _center; + private final Map _dataPoints; + + public Room(Player player, Location center, Map dataPoints) + { + _player = player; + _center = center; + _dataPoints = dataPoints; + } + + public Player getPlayer() + { + return _player; + } + + public Location getCenter() + { + return _center; + } + + public Map getDataPoints() + { + return _dataPoints; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/RoomedSoloGame.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/RoomedSoloGame.java new file mode 100644 index 000000000..7f8ddb937 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/game/roomed/RoomedSoloGame.java @@ -0,0 +1,93 @@ +package mineplex.game.nano.game.roomed; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.scoreboard.NameTagVisibility; + +import mineplex.core.common.block.schematic.Schematic; +import mineplex.core.common.block.schematic.UtilSchematic; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.GameType; +import mineplex.game.nano.game.ScoredSoloGame; +import mineplex.game.nano.game.event.PlayerGameApplyEvent; + +public abstract class RoomedSoloGame extends ScoredSoloGame +{ + + private static final int MAX_XZ = 5; + + protected final Map _rooms; + + private Location _spawn, _relative; + private Schematic _schematic; + private int _x = -MAX_XZ, _z = -MAX_XZ; + + public RoomedSoloGame(NanoManager manager, GameType gameType, String[] description) + { + super(manager, gameType, description); + + _rooms = new HashMap<>(); + + _scoreboardComponent.setSetupSettingsConsumer((player, team, scoreboardTeam) -> scoreboardTeam.setNameTagVisibility(NameTagVisibility.NEVER)); + } + + @Override + protected void parseData() + { + _spawn = _playersTeam.getSpawn(); + _relative = _mineplexWorld.getMin().clone(); + _schematic = UtilSchematic.createSchematic(_mineplexWorld.getMin(), _mineplexWorld.getMax()); + + Location min = _mineplexWorld.getMin(), max = _mineplexWorld.getMax(); + + min.setX(-256); + min.setZ(-256); + max.setX(256); + max.setZ(256); + } + + @Override + public void disable() + { + _schematic = null; + } + + protected abstract T addPlayer(Player player, Location location, Map localPoints); + + @EventHandler + public void respawn(PlayerGameApplyEvent event) + { + Player player = event.getPlayer(); + Room room = createRoom(player); + + event.setRespawnLocation(event.getRespawnLocation().add(room.getCenter())); + } + + private T createRoom(Player player) + { + if (++_x > MAX_XZ) + { + _x = -MAX_XZ; + _z++; + } + + double xAdd = _x * _schematic.getLength(), zAdd = _z * _schematic.getWidth(); + + getManager().runSyncLater(() -> _schematic.paste(_relative.clone().add(xAdd, 0, zAdd), true, false, false), 1); + + Map> globalPoints = _mineplexWorld.getIronLocations(); + Map localPoints = new HashMap<>(globalPoints.size()); + + globalPoints.forEach((key, locations) -> localPoints.put(key, locations.get(0).clone().add(xAdd, 0, zAdd))); + + T room = addPlayer(player, _spawn.clone().add(xAdd, 0, zAdd), localPoints); + _rooms.put(player, room); + + return room; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/AFKManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/AFKManager.java new file mode 100644 index 000000000..38da446f4 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/AFKManager.java @@ -0,0 +1,159 @@ +package mineplex.game.nano.lobby; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +import mineplex.core.MiniClientPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Intent; +import mineplex.core.portal.Portal; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; +import mineplex.game.nano.lobby.AFKManager.AFKData; + +@ReflectivelyCreateMiniPlugin +public class AFKManager extends MiniClientPlugin +{ + + public enum Perm implements Permission + { + BYPASS_AFK_KICK + } + + private static final long KICK_WARNING_TIME = TimeUnit.SECONDS.toMillis(60); + private static final long KICK_TIME = TimeUnit.SECONDS.toMillis(70); + + private final NanoManager _manager; + + private AFKManager() + { + super("AFK"); + + _manager = require(NanoManager.class); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.MOD.setPermission(Perm.BYPASS_AFK_KICK, true, true); + + if (UtilServer.isTestServer()) + { + PermissionGroup.QAT.setPermission(Perm.BYPASS_AFK_KICK, true, true); + } + } + + @Override + protected AFKData addPlayer(UUID uuid) + { + return new AFKData(); + } + + @EventHandler + public void updateAFK(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || _manager.getGame() == null) + { + return; + } + + for (Player player : UtilServer.getPlayersCollection()) + { + if (_manager.getClientManager().Get(player).hasPermission(Perm.BYPASS_AFK_KICK) || !_manager.getGame().isAlive(player)) + { + continue; + } + + AFKData data = Get(player); + + if (data.Last == null || data.LastMovement == 0) + { + data.Last = player.getLocation(); + data.LastMovement = System.currentTimeMillis(); + continue; + } + + Location location = player.getLocation(); + + if (location.getWorld().equals(data.Last.getWorld())) + { + if (UtilMath.offsetSquared(location, data.Last) > 1) + { + data.LastMovement = System.currentTimeMillis(); + data.Informed = false; + } + else if (UtilTime.elapsed(data.LastMovement, KICK_TIME)) + { + player.sendMessage(""); + player.sendMessage(C.cGoldB + " YOU HAVE BEEN KICKED FOR AFK!"); + player.sendMessage(""); + player.playSound(player.getLocation(), Sound.ENDERDRAGON_GROWL, 1, 1); + Portal.getInstance().sendPlayerToGenericServer(player, GenericServer.HUB, Intent.KICK); + } + else if (UtilTime.elapsed(data.LastMovement, KICK_WARNING_TIME) && !data.Informed) + { + player.sendMessage(""); + player.sendMessage(C.cGold + " If you do not move soon you will be kicked for AFK!"); + player.sendMessage(""); + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1); + data.Informed = true; + } + } + + data.Last = location; + } + } + + @EventHandler + public void playerIn(PlayerStateChangeEvent event) + { + if (event.isAlive()) + { + Get(event.getPlayer()).LastMovement = System.currentTimeMillis(); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void entityShootBow(EntityShootBowEvent event) + { + if (event.getEntity() instanceof Player) + { + Get((Player) event.getEntity()).LastMovement = System.currentTimeMillis(); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void playerTeleport(PlayerTeleportEvent event) + { + AFKData data = Get(event.getPlayer()); + data.Last = event.getTo(); + } + + class AFKData + { + + Location Last; + long LastMovement; + boolean Informed; + + } + +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/LobbyManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/LobbyManager.java new file mode 100644 index 000000000..5c859117c --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/LobbyManager.java @@ -0,0 +1,175 @@ +package mineplex.game.nano.lobby; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerLoginEvent.Result; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.powerplayclub.PowerPlayClubRepository; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.NanoPlayer; + +@ReflectivelyCreateMiniPlugin +public class LobbyManager extends GameManager +{ + + public enum Perm implements Permission + { + BETA_WHITELIST, + } + + private final PowerPlayClubRepository _powerPlayClub; + + private final MineplexWorld _mineplexWorld; + private final Location _spawn; + + private boolean _infoTick; + + private LobbyManager() + { + super("Lobby"); + + _powerPlayClub = new PowerPlayClubRepository(_plugin, _manager.getClientManager(), _manager.getDonationManager()); + + _mineplexWorld = new MineplexWorld(Bukkit.getWorlds().get(0)); + _spawn = _mineplexWorld.getSpongeLocation("SPAWN"); + + _mineplexWorld.getWorld().setSpawnLocation(_spawn.getBlockX(), _spawn.getBlockY(), _spawn.getBlockZ()); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.ETERNAL.setPermission(Perm.BETA_WHITELIST, true, true); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void playerLogin(PlayerLoginEvent event) + { + Player player = event.getPlayer(); + + if (_manager.getClientManager().Get(player).hasPermission(Perm.BETA_WHITELIST) || _powerPlayClub.getCachedData(player).isSubscribed()) + { + return; + } + + event.disallow(Result.KICK_WHITELIST, "Only players with Eternal or PPC can participate in the BETA."); + } + + @EventHandler + public void updateInfo(UpdateEvent event) + { + if (event.getType() != UpdateType.MIN_01) + { + return; + } + + String info = C.cPurpleB + "INFO" + C.cDGrayB + "> " + C.cPurple; + + if (_infoTick) + { + info += C.cGreen + "Nano Games" + C.cPurple + " are still in development and do not represent a finished product. You can leave feedback and report bugs " + C.cYellowB + "HERE" + C.cPurple + "."; + } + else + { + info += "This game goes on forever! If you ever want to cash out on your rewards, you can do so at any time using the " + C.cGreen + "Cash Out Clock" + C.cPurple + " or " + C.cYellow + "/hub" + C.cPurple + "!"; + } + + _infoTick = !_infoTick; + + BaseComponent[] components = TextComponent.fromLegacyText(info); + HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Click here to visit the forums.") + .color(ChatColor.YELLOW) + .create()); + ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.OPEN_URL, "https://www.mineplex.com/forums/m/11929946/viewforum/3983713"); + + for (BaseComponent component : components) + { + component.setHoverEvent(hoverEvent); + component.setClickEvent(clickEvent); + } + + for (Player player : UtilServer.getPlayersCollection()) + { + player.spigot().sendMessage(components); + } + } + + @EventHandler + public void updateWaiting(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOWER || _manager.getGame() != null) + { + return; + } + + UtilTextMiddle.display(null, C.cGreen + "Waiting for players...", 0, 40, 10, UtilServer.getPlayers()); + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + if (_manager.getGame() != null) + { + return; + } + + Player player = event.getPlayer(); + + joinLobby(player); + } + + public void joinLobby(Player player) + { + NanoPlayer.clear(_manager, player); + NanoPlayer.setSpectating(player, false); + + player.teleport(_spawn); + } + + public void ensureInLobby() + { + for (Player player : UtilServer.getPlayersCollection()) + { + if (player.getWorld().equals(_mineplexWorld.getWorld())) + { + continue; + } + + player.sendMessage(F.main(_manager.getName(), "Not enough players to start. Returning you to the lobby.")); + joinLobby(player); + } + } + + public MineplexWorld getMineplexWorld() + { + return _mineplexWorld; + } + + public Location getSpawn() + { + return _spawn; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/ReturnToHubManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/ReturnToHubManager.java new file mode 100644 index 000000000..44807d3ed --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/lobby/ReturnToHubManager.java @@ -0,0 +1,132 @@ +package mineplex.game.nano.lobby; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.command.CommandBase; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilEvent; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.portal.GenericServer; +import mineplex.core.portal.Intent; +import mineplex.core.portal.Portal; +import mineplex.core.recharge.Recharge; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.game.Game.GameState; +import mineplex.game.nano.game.event.GameStateChangeEvent; +import mineplex.game.nano.game.event.PlayerStateChangeEvent; + +@ReflectivelyCreateMiniPlugin +public class ReturnToHubManager extends GameManager +{ + + public enum Perm implements Permission + { + RETURN_TO_HUB_COMMAND + } + + private static final ItemStack HUB_CLOCK = new ItemBuilder(Material.WATCH) + .setTitle(C.cGreen + "Cash Out") + .addLore("", "Click to return to the hub and", "receive all your rewards from this game!") + .build(); + + private ReturnToHubManager() + { + super("Return To Hub"); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.PLAYER.setPermission(Perm.RETURN_TO_HUB_COMMAND, true, true); + } + + @Override + public void addCommands() + { + addCommand(new CommandBase(this, Perm.RETURN_TO_HUB_COMMAND, "hub", "lobby", "leave") + { + @Override + public void Execute(Player caller, String[] args) + { + sendToHub(caller); + } + }); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void playerOut(PlayerStateChangeEvent event) + { + if (event.isAlive()) + { + return; + } + + Player player = event.getPlayer(); + + runSyncLater(() -> + { + if (player.isOnline() && !_manager.getGame().isAlive(player)) + { + giveClock(player); + } + }, 20); + } + + @EventHandler + public void playerInteractClock(PlayerInteractEvent event) + { + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (!HUB_CLOCK.equals(itemStack)) + { + return; + } + + sendToHub(player); + } + + @EventHandler(priority = EventPriority.HIGH) + public void prepare(GameStateChangeEvent event) + { + if (event.getState() != GameState.Prepare) + { + return; + } + + for (Player player : _manager.getSpectators()) + { + giveClock(player); + } + } + + private void giveClock(Player player) + { + player.getInventory().setItem(8, HUB_CLOCK); + } + + private void sendToHub(Player player) + { + if (!Recharge.Instance.use(player, "Return To Hub", 2000, false, false)) + { + return; + } + + Portal.getInstance().sendPlayerToGenericServer(player, GenericServer.HUB, Intent.PLAYER_REQUEST); + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/status/GameStatusManager.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/status/GameStatusManager.java new file mode 100644 index 000000000..c0d1becc5 --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/status/GameStatusManager.java @@ -0,0 +1,136 @@ +package mineplex.game.nano.status; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerLoginEvent.Result; +import org.bukkit.event.server.ServerListPingEvent; + +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.account.CoreClient; +import mineplex.core.account.permissions.Permission; +import mineplex.core.account.permissions.PermissionGroup; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilServer; +import mineplex.core.game.status.GameInfo; +import mineplex.core.game.status.GameInfo.GameDisplayStatus; +import mineplex.core.game.status.GameInfo.GameJoinStatus; +import mineplex.game.nano.GameManager; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game; + +@ReflectivelyCreateMiniPlugin +public class GameStatusManager extends GameManager +{ + + public enum Perm implements Permission + { + JOIN_FULL, + JOIN_FULL_STAFF, + } + + private GameStatusManager() + { + super("Game Status"); + + generatePermissions(); + } + + private void generatePermissions() + { + PermissionGroup.ULTRA.setPermission(Perm.JOIN_FULL, true, true); + PermissionGroup.TRAINEE.setPermission(Perm.JOIN_FULL_STAFF, true, true); + } + + @EventHandler + public void motdPing(ServerListPingEvent event) + { + if (UtilServer.isTestServer(false)) + { + event.setMotd(C.cAqua + "Private Mineplex Test Server"); + return; + } + + Game game = _manager.getGame(); + String gameName = null, map = null; + GameDisplayStatus status = GameDisplayStatus.WAITING; + + if (game != null) + { + status = GameDisplayStatus.ALWAYS_OPEN; + gameName = game.getGameType().getName(); + + if (game.getMineplexWorld() != null) + { + map = game.getMineplexWorld().getMapName(); + } + } + + GameJoinStatus joinable = getJoinable(); + + if (joinable == GameJoinStatus.CLOSED) + { + status = GameDisplayStatus.IN_PROGRESS; + } + + event.setMotd(new GameInfo(NanoManager.getGameDisplay(), gameName, map, -1, null, null, status, joinable).toString()); + } + + @EventHandler + public void playerLogin(PlayerLoginEvent event) + { + Player player = event.getPlayer(); + CoreClient client = _manager.getClientManager().Get(player); + GameJoinStatus joinable = getJoinable(); + + if (joinable != GameJoinStatus.OPEN) + { + if (client.hasPermission(Perm.JOIN_FULL_STAFF)) + { + event.allow(); + return; + } + + boolean canOverflow = client.hasPermission(Perm.JOIN_FULL) || _manager.getDonationManager().Get(player).ownsUnknownSalesPackage(_manager.getServerGroup().getServerType() + " ULTRA"); + + if (canOverflow) + { + if (joinable == GameJoinStatus.RANKS_ONLY) + { + event.allow(); + } + else + { + event.disallow(Result.KICK_OTHER, C.Bold + "Server has reached max capacity for gameplay purposes."); + } + } + else + { + if (joinable == GameJoinStatus.RANKS_ONLY) + { + event.disallow(Result.KICK_OTHER, C.Bold + "Server has reached max capacity for gameplay purposes."); + } + else + { + event.disallow(Result.KICK_OTHER, C.Bold + "Server Full > Purchase Ultra at www.mineplex.com/shop"); + } + } + } + } + + private GameJoinStatus getJoinable() + { + if (Bukkit.getOnlinePlayers().size() >= Bukkit.getServer().getMaxPlayers()) + { + if ((double) Bukkit.getServer().getOnlinePlayers().size() / Bukkit.getMaxPlayers() > 1.2) + { + return GameJoinStatus.CLOSED; + } + + return GameJoinStatus.RANKS_ONLY; + } + + return GameJoinStatus.OPEN; + } +} diff --git a/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/world/GameWorld.java b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/world/GameWorld.java new file mode 100644 index 000000000..45598aaec --- /dev/null +++ b/Plugins/Mineplex.Game.Nano/src/mineplex/game/nano/world/GameWorld.java @@ -0,0 +1,145 @@ +package mineplex.game.nano.world; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import org.bukkit.Difficulty; +import org.bukkit.World; +import org.bukkit.WorldCreator; + +import mineplex.core.common.util.FileUtil; +import mineplex.core.common.util.MapUtil; +import mineplex.core.common.util.WorldUtil; +import mineplex.core.common.util.ZipUtil; +import mineplex.core.common.util.worldgen.WorldGenCleanRoom; +import mineplex.core.world.MineplexWorld; +import mineplex.game.nano.NanoManager; +import mineplex.game.nano.game.Game; + +public class GameWorld +{ + + private static final String DIRECTORY_PREFIX = "Game"; + private static final File GAME_ID_FILE = new File("GameId.dat"); + + public static void deleteOldFolders(NanoManager manager) + { + File[] files = new File(".").listFiles((dir, name) -> name.startsWith(DIRECTORY_PREFIX)); + + if (files == null) + { + return; + } + + for (File file : files) + { + if (!file.isDirectory()) + { + continue; + } + + FileUtil.DeleteFolder(file); + manager.log("Deleted Old Game: " + file.getName()); + } + } + + public static int getNextId() throws IOException, NumberFormatException + { + int write = 0; + + if (GAME_ID_FILE.exists()) + { + write = Integer.parseInt(Files.readAllLines(GAME_ID_FILE.toPath()).get(0)); + } + + BufferedWriter writer = Files.newBufferedWriter(GAME_ID_FILE.toPath()); + writer.write(String.valueOf(write + 1)); + writer.close(); + + return write; + } + + private final Game _game; + private final File _mapZip; + private final int _id; + + private World _world; + + public GameWorld(Game game, File mapZip) + { + _game = game; + _mapZip = mapZip; + + int id = 0; + + try + { + id = getNextId(); + } + catch (Exception e) + { + GAME_ID_FILE.delete(); + e.printStackTrace(); + } + + _id = id; + game.getManager().log("Game Id: " + id); + } + + public void loadWorld() + { + String mapName = _mapZip.getName(); + int dotIndex = mapName.lastIndexOf('.'); + mapName = dotIndex == -1 ? mapName : mapName.substring(0, dotIndex); + String directory = DIRECTORY_PREFIX + _id + "_" + _game.getGameType().getName() + "_" + mapName; + + _game.getManager().runAsync(() -> + { + new File(directory + File.separator + "region").mkdirs(); + new File(directory + File.separator + "data").mkdirs(); + + ZipUtil.UnzipToDirectory(_mapZip.getAbsolutePath(), directory); + + _game.getManager().runSync(() -> + { + WorldCreator creator = new WorldCreator(directory); + creator.generator(new WorldGenCleanRoom()); + _world = WorldUtil.LoadWorld(creator); + + if (_world == null) + { + return; + } + + _world.setDifficulty(Difficulty.HARD); + _world.setTime(6000); + _world.setGameRuleValue("showDeathMessages", "false"); + _world.setGameRuleValue("doDaylightCycle", "false"); + _world.setGameRuleValue("keepInventory", "true"); + + _game.getManager().runAsync(() -> + { + MineplexWorld mineplexWorld = new MineplexWorld(_world); + + _game.getManager().runSync(() -> _game.setupMineplexWorld(mineplexWorld)); + }); + }); + }); + } + + public void unloadWorld() + { + if (_world == null) + { + return; + } + + MapUtil.UnloadWorld(_game.getManager().getPlugin(), _world); + MapUtil.ClearWorldReferences(_world.getName()); + FileUtil.DeleteFolder(_world.getWorldFolder()); + + _world = null; + } +} diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java index 5e8dc280e..b64b7a87f 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java @@ -126,6 +126,7 @@ public class ServerManager extends MiniPlugin .put("Champions", new String[]{"DOM", "CTF"}) .put("Clans", new String[]{"ClansHub", "Clans"}) .put("Retro", new String[]{"RETRO"}) + .put("Nano Games", new String[]{"NANO"}) .build(); private final QuickShop _quickShop; @@ -518,6 +519,7 @@ public class ServerManager extends MiniPlugin switch (info.getStatus()) { + case ALWAYS_OPEN: case WAITING: case VOTING: return false; diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/game/ServerGameMenu.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/game/ServerGameMenu.java index b429be5fc..9aae610ff 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/game/ServerGameMenu.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/game/ServerGameMenu.java @@ -198,7 +198,7 @@ public class ServerGameMenu extends ShopPageBase } }); - add(29, Material.WOOD, "Master Builders", C.cBlueB + "Master Builders " + C.cGray + "Creative Build", new String[] + add(29, Material.WOOD, "Master Builders", C.cGreenB + "Master Builders " + C.cGray + "Creative Build", new String[] { "Wow so pretty! 10/10", "Time to show off your real building skills", @@ -208,7 +208,7 @@ public class ServerGameMenu extends ShopPageBase C.cWhite + "Perfect for Solo or Parties up to 12." }, "Master_Builders"); - add(30, Material.BOOK_AND_QUILL, "Draw My Thing", C.cBlueB + "Draw My Thing " + C.cGray + "Pictionary", new String[] + add(30, Material.BOOK_AND_QUILL, "Draw My Thing", C.cGreenB + "Draw My Thing " + C.cGray + "Pictionary", new String[] { "Basically Picasso", "Draw your way to victory in this skillful game", @@ -217,7 +217,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 8." }, "Draw_My_Thing"); - add(31, Material.LAVA_BUCKET, "Micro Battles", C.cBlueB + "Micro Battles " + C.cGray + "Fast Paced Team PvP", new String[] + add(31, Material.LAVA_BUCKET, "Micro Battles", C.cGreenB + "Micro Battles " + C.cGray + "Fast Paced Team PvP", new String[] { "It fits in your pocket!", "A 4v4v4v4 basic pvp battle to see who is left", @@ -225,7 +225,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 4." }, ARCADE_BOOSTER_GROUP); - add(32, Material.NOTE_BLOCK, "Mixed Arcade", C.cBlueB + "Mixed Arcade " + C.cGray + "Multiple Quick Games", new String[] + add(32, Material.NOTE_BLOCK, "Mixed Arcade", C.cGreenB + "Mixed Arcade " + C.cGray + "Multiple Quick Games", new String[] { "It's a huge party!", "Switch between multiple different gamemodes", @@ -233,7 +233,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 16." }, ARCADE_BOOSTER_GROUP); - add(33, Material.WOOL, 3, "Turf Wars", C.cBlueB + "Turf Wars " + C.cGray + "Team PvP", new String[] + add(33, Material.WOOL, 3, "Turf Wars", C.cGreenB + "Turf Wars " + C.cGray + "Team PvP", new String[] { "Fight for your color!", "A blue vs red battle to take the most land!", @@ -242,7 +242,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 8." }, ARCADE_BOOSTER_GROUP); - add(38, Material.QUARTZ_BLOCK, "Speed Builders", C.cGreenB + "Speed Builders " + C.cGray + "Building Memory Game", new String[] + add(38, Material.QUARTZ_BLOCK, "Speed Builders", C.cYellowB + "Speed Builders " + C.cGray + "Building Memory Game", new String[] { "How good is your memory?", "You only have a short time to remember the build", @@ -251,7 +251,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties of 8." }, "Speed_Builders"); - add(39, Material.GRASS, "Block Hunt", C.cGreenB + "Block Hunt " + C.cGray + "Hide & Seek", new String[] + add(39, Material.GRASS, "Block Hunt", C.cYellowB + "Block Hunt " + C.cGray + "Hide & Seek", new String[] { "Shhh, they can see you!", "A cat and mouse game of your favorite", @@ -260,7 +260,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 16." }, "Block_Hunt"); - add(40, Material.CAKE, 0, "Cake Wars", C.cGreenB + "Cake Wars " + C.cGray + "4 Teams/Duos PvP", new String[] + add(40, Material.CAKE, 0, "Cake Wars", C.cYellowB + "Cake Wars " + C.cGray + "4 Teams/Duos PvP", new String[] { "Winner Winner Cake For Dinner", "A challenging 4 or 8 team battle to protect your", @@ -269,7 +269,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Parties of 2 to 4." }, "Cake_Wars"); - add(41, Material.DIAMOND_SWORD, "Survival Games", C.cGreenB + "Survival Games " + C.cGray + "Solo/Team Survival", new String[] + add(41, Material.DIAMOND_SWORD, "Survival Games", C.cYellowB + "Survival Games " + C.cGray + "Solo/Team Survival", new String[] { "Trust no one.", "A free for all of pvp madness. Go straight for the", @@ -278,7 +278,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties of 2." }, "Survival_Games"); - add(42, Material.FEATHER, "Skywars", C.cGreenB + "Skywars " + C.cGray + "Solo/Team Survival", new String[] + add(42, Material.FEATHER, "Skywars", C.cYellowB + "Skywars " + C.cGray + "Solo/Team Survival", new String[] { "It's kinda high up here...", "A war in the sky. Spawn on a floating island and", @@ -321,7 +321,7 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties up to 5." }, "Champions"); - add(51, Material.IRON_SWORD, "Clans", C.cRedB + "Clans " + C.cGray + "Factions Survival", new String[] + add(51, Material.IRON_DOOR, "Clans", C.cRedB + "Clans " + C.cGray + "Factions Survival", new String[] { "Hide. Fight. War. Win.", "Fight in this medieval land with Champions classes to", @@ -330,9 +330,22 @@ public class ServerGameMenu extends ShopPageBase "", C.cWhite + "Perfect for Solo or Parties of any size." }, null); + add(13, new ItemBuilder(Material.EGG), "Nano Games", C.cYellow + C.Scramble + "ABC" + C.cGreenB + " Nano Games " + C.cYellow + C.Scramble + "DEF" + C.cGray + " Limited Beta Game", new String[] + { + "Game Over? Straight into the next!", + "Want to enjoy constant action with no", + "waiting around? Then Nano Games are perfect", + "for you. Play over 20 quick games. Once", + "you're down hit the Cash Out Clock and", + "claim your rewards.", + "", + C.cWhite + "Limited Beta for " + C.cDAquaB + "ETERNAL" + C.cWhite + " and " + C.cAquaB + "PPC" + C.cWhite + "!", + "", + C.cWhite + "Perfect for Solo or Parties up to 16." + }, "Nano_Games", true); - fillRow(27, (byte) 11); - fillRow(36, (byte) 5); + fillRow(27, (byte) 5); + fillRow(36, (byte) 4); fillRow(45, (byte) 14); } @@ -347,6 +360,11 @@ public class ServerGameMenu extends ShopPageBase } private void add(int slot, ItemBuilder builder, String npcName, String title, String[] lore, String boosterGroup) + { + add(slot, builder, npcName, title, lore, boosterGroup, false); + } + + private void add(int slot, ItemBuilder builder, String npcName, String title, String[] lore, String boosterGroup, boolean feature) { if (boosterGroup != null) { @@ -363,6 +381,11 @@ public class ServerGameMenu extends ShopPageBase } } + if (feature) + { + builder.setGlow(true); + } + if (title != null) { builder.setTitle(title); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/server/ServerSelectionPage.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/server/ServerSelectionPage.java index 7f12e4321..faf34121b 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/server/ServerSelectionPage.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ui/server/ServerSelectionPage.java @@ -219,10 +219,13 @@ public class ServerSelectionPage extends ShopPageBaseMineplex.ServerMonitor Mineplex.StaffServer Mineplex.Votifier + Mineplex.Game.Nano Nautilus.Game.Arcade Nautilus.Game.Arcade.UHC.WorldGen - mavericks-review-hub mineplex-game-gemhunters mineplex-google-sheets