package com.github.jamesnorris.ablockalypse.event.bukkit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.Event.Result; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.material.Lever; import com.github.jamesnorris.ablockalypse.Ablockalypse; import com.github.jamesnorris.ablockalypse.DataContainer; import com.github.jamesnorris.ablockalypse.aspect.Game; import com.github.jamesnorris.ablockalypse.aspect.MapData; import com.github.jamesnorris.ablockalypse.aspect.MysteryBox; import com.github.jamesnorris.ablockalypse.aspect.Passage; import com.github.jamesnorris.ablockalypse.aspect.PowerSwitch; import com.github.jamesnorris.ablockalypse.aspect.Teleporter; import com.github.jamesnorris.ablockalypse.aspect.ZAMob; import com.github.jamesnorris.ablockalypse.aspect.ZAPlayer; import com.github.jamesnorris.ablockalypse.enumerated.Local; import com.github.jamesnorris.ablockalypse.enumerated.Setting; import com.github.jamesnorris.ablockalypse.enumerated.ZAEffect; import com.github.jamesnorris.ablockalypse.enumerated.ZAEnchantment; import com.github.jamesnorris.ablockalypse.enumerated.ZAPerk; import com.github.jamesnorris.ablockalypse.event.GameCreateEvent; import com.github.jamesnorris.ablockalypse.event.GameSignClickEvent; import com.github.jamesnorris.ablockalypse.queue.QueuedPlayerInteractData; import com.github.jamesnorris.ablockalypse.threading.inherent.TeleportTask; import com.github.jamesnorris.ablockalypse.threading.inherent.TeleporterLinkageTimerTask; import com.github.jamesnorris.ablockalypse.utility.AblockalypseUtility; import com.github.jamesnorris.ablockalypse.utility.BukkitUtility; import com.github.jamesnorris.ablockalypse.utility.BuyableItemData; import com.github.jamesnorris.ablockalypse.utility.Cube; import com.github.jamesnorris.ablockalypse.utility.Cuboid; import com.github.jamesnorris.ablockalypse.utility.HitThroughWallShot; import com.github.jamesnorris.mcshot.Hit; import com.github.jamesnorris.mcshot.HitBox; import com.github.jamesnorris.mcshot.Shot; import com.github.jamesnorris.mcshot.type.EntityHitBox; public class PlayerInteract implements Listener { public static ArrayList<Game> fireSale = new ArrayList<Game>();// TODO queue all of these remaining lists/maps public static HashMap<ZAPlayer, Teleporter> mainframeLinkers = new HashMap<ZAPlayer, Teleporter>(); public static HashMap<ZAPlayer, TeleporterLinkageTimerTask> mainframeLinkers_Timers = new HashMap<ZAPlayer, TeleporterLinkageTimerTask>(); public static HashMap<String, Game> passagePlayers = new HashMap<String, Game>(); public static HashMap<String, String> mapDataSavePlayers = new HashMap<String, String>(); private static HashMap<String, Location> mapDataPoint1SaveClickers = new HashMap<String, Location>(); public static HashMap<String, String> mapDataLoadPlayers = new HashMap<String, String>(); private DataContainer data = Ablockalypse.getData(); public static BlockingQueue<QueuedPlayerInteractData> queue = new LinkedBlockingQueue<QueuedPlayerInteractData>(); public boolean isPassage(Block block) { for (Passage passage : data.getObjectsOfType(Passage.class)) { if (passage.getDefiningBlocks().contains(block)) { return true; } } return false; } /* The event called when a player clicks a block. * * USED: * *When a ZAPlayer clicks a sign, to check the lines for strings that trigger a response. */ @EventHandler(priority = EventPriority.HIGHEST) public void PIE(PlayerInteractEvent event) { for (QueuedPlayerInteractData data : queue) { if ((data.getKey().equals(event.getPlayer().getName()) || data.getKey().equals(QueuedPlayerInteractData.ANY_PLAYER)) && data.isCompatible(event)) { data.importPIE(event); data.run(); if (data.removeAfterRun()) { queue.remove(data); } return; } } Block block = event.getClickedBlock(); Player player = event.getPlayer(); Action action = event.getAction(); if (block != null) { Location loc = block.getLocation(); if (!data.isZAPlayer(player) && mapDataSavePlayers.containsKey(player.getName()) && action == Action.RIGHT_CLICK_BLOCK) { if (!mapDataPoint1SaveClickers.containsKey(player.getName())) { mapDataPoint1SaveClickers.put(player.getName(), block.getLocation()); player.sendMessage(ChatColor.GRAY + "Please click the other corner of the map."); return; } else { boolean saved = new MapData(mapDataSavePlayers.get(player.getName())).save(new Cuboid(mapDataPoint1SaveClickers.get(player.getName()), block.getLocation())); mapDataPoint1SaveClickers.remove(player.getName()); mapDataSavePlayers.remove(player.getName()); String successful = saved ? ChatColor.GREEN + "successfully" + ChatColor.RESET : ChatColor.RED + "unsuccessfully" + ChatColor.RESET; player.sendMessage(ChatColor.GRAY + "Mapdata saved " + successful + ChatColor.GRAY + "."); } } else if (!data.isZAPlayer(player) && mapDataLoadPlayers.containsKey(player.getName()) && action == Action.RIGHT_CLICK_BLOCK) { boolean loaded = MapData.getFromGame(mapDataLoadPlayers.get(player.getName())).load(block.getLocation()); mapDataLoadPlayers.remove(player.getName()); String successful = loaded ? ChatColor.GREEN + "successfully" + ChatColor.RESET : ChatColor.RED + "unsuccessfully" + ChatColor.RESET; player.sendMessage(ChatColor.GRAY + "Mapdata loaded " + successful + "."); } else if (!data.isZAPlayer(player) && data.isGameObject(loc)) { event.setCancelled(true); } else if ((block.getType() == Material.SIGN || block.getType() == Material.SIGN_POST || block.getType() == Material.WALL_SIGN) && action == Action.RIGHT_CLICK_BLOCK) { Sign s = (Sign) block.getState(); if (s.getLine(0).equalsIgnoreCase(Local.BASE_STRING.getSetting())) { event.setUseInteractedBlock(Result.DENY); runLines(s, player); return; } return; } else if (data.isZAPlayer(player)) { if (!BlockPlace.shouldBePlaced(player.getItemInHand().getType())) { event.setUseItemInHand(Result.DENY); } ZAPlayer zap = data.getZAPlayer(player); Game game = zap.getGame(); if (block.getType() == Material.CHEST && action == Action.RIGHT_CLICK_BLOCK) { event.setUseInteractedBlock(Result.DENY); Location l = block.getLocation(); if (data.isMysteryChest(l)) { MysteryBox mc = data.getMysteryChest(l); if (mc != null && mc.isActive()) { mc.openToRandomItem(zap); } else { player.sendMessage(ChatColor.RED + "That chest is not active!"); event.setCancelled(true); return; } } } else if (block.getType() == Material.WOOD_DOOR || block.getType() == Material.IRON_DOOR) { event.setCancelled(true); } else if (block.getType() == Material.LEVER && action == Action.RIGHT_CLICK_BLOCK) { Lever lever = (Lever) block.getState().getData(); if (lever.isPowered()) { player.sendMessage(lever.isPowered() ? ChatColor.GRAY + "The switch is on." : ChatColor.RED + "That switch is in use by another game!"); event.setUseInteractedBlock(Result.DENY); event.setUseItemInHand(Result.DENY); event.setCancelled(true); return; } new PowerSwitch(game, loc, lever); } else if (!block.getType().isOccluding() && (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK)) { // through-fence damage ItemStack handItem = player.getItemInHand(); short damage = handItem == null ? 1/* hand damage */ : handItem.getDurability(); HitThroughWallShot shotData = new HitThroughWallShot(damage); Shot shot = new Shot(player.getEyeLocation(), shotData); List<Hit> results = shot.shoot(shot.arrangeClosest(data.getObjectsOfType(HitBox.class))); if (results.isEmpty()) { return; } Hit closestHit = results.get(0); if (closestHit == null || !(closestHit.getBoxHit() instanceof EntityHitBox)) { return; } Entity hitBoxEntity = ((EntityHitBox) closestHit.getBoxHit()).getEntity(); if (!(hitBoxEntity instanceof LivingEntity)) { return; } ZAMob zam = data.getZAMob((LivingEntity) hitBoxEntity); if (!zam.getGame().getUUID().equals(zap.getGame().getUUID())) { return; } zam.getEntity().damage(shotData.getDamage(0), player); return; } else if (action == Action.RIGHT_CLICK_BLOCK) { if (block.getType() == Material.CHEST) { event.setUseInteractedBlock(Result.DENY); } if (BukkitUtility.locationMatch(block.getLocation(), game.getMainframe().getLocation(), 2)) { // mainframe if (PlayerInteract.mainframeLinkers.containsKey(zap)) { TeleporterLinkageTimerTask tltt = PlayerInteract.mainframeLinkers_Timers.get(zap); if (tltt.canBeLinked()) { player.sendMessage(ChatColor.GREEN + "Teleporter linked!"); tltt.setLinked(true); PlayerInteract.mainframeLinkers.get(zap).setLinked(true); } PlayerInteract.mainframeLinkers.remove(zap); PlayerInteract.mainframeLinkers_Timers.remove(zap); } } else if (data.isTeleporter(block.getLocation())) { Teleporter tele = data.getTeleporter(block.getLocation()); if (!tele.isPowered() && (Boolean) Setting.TELEPORTERS_REQUIRE_POWER.getSetting()) { return; } // not mainframe double distanceSquared = Double.MAX_VALUE; double time = -1; boolean requiresLinkage = true; Cube cube = new Cube(block.getLocation(), 2); for (Location sqLoc : cube.getLocations()) { if (sqLoc.getBlock().getState() instanceof Sign) { Sign sign = (Sign) sqLoc.getBlock().getState(); String[] lines = sign.getLines(); if (lines[0].equalsIgnoreCase(Local.BASE_STRING.getSetting()) && lines[1].equalsIgnoreCase(Local.BASE_TELEPORTER_SETTINGS_STRING.getSetting())) { try { if (sqLoc.distanceSquared(block.getLocation()) < distanceSquared) { requiresLinkage = Boolean.parseBoolean(lines[2]); time = Double.parseDouble(lines[3]); distanceSquared = sqLoc.distanceSquared(block.getLocation()); } } catch (Exception e) { // nothing } } } } tele.refresh(); if (data.getTeleporter(block.getLocation()).isLinked() || !requiresLinkage) { // this teleporter is linked to the mainframe... if (!zap.isTeleporting()) { player.sendMessage(ChatColor.GRAY + "Teleportation sequence started..."); new TeleportTask(zap, (Integer) Setting.TELEPORT_TIME.getSetting(), true); return; } else { player.sendMessage(ChatColor.GRAY + "You are already teleporting!"); return; } } else { // this teleporter is not linked to the mainframe... time = time == -1 ? (int) (loc.distanceSquared(game.getMainframe().getLocation()) * .1) : time;// 1 second per block difference (4.5 approx sqrt 20) tele.setLinkTime(time); PlayerInteract.mainframeLinkers.put(zap, tele); PlayerInteract.mainframeLinkers_Timers.put(zap, new TeleporterLinkageTimerTask(game.getMainframe(), zap, (int) time * 20, true)); // difference player.sendMessage(ChatColor.GRAY + "You now have " + time + " seconds to link the teleporter to the mainframe!"); } } } } } } /** * Checks the lines of the sign for strings in the config, that enable changes to be made to the player. * * @param sign The sign to run lines from * @param player The player to affect if the lines are run through */ @SuppressWarnings("deprecation") public void runLines(Sign sign, Player player) { String l1 = sign.getLine(0); String l2 = sign.getLine(1); String l3 = sign.getLine(2); // String l4 = sign.getLine(3);//UNUSED if (l1.equalsIgnoreCase(Local.BASE_STRING.getSetting())) { GameSignClickEvent gsce = new GameSignClickEvent(sign, player); Bukkit.getPluginManager().callEvent(gsce); if (!gsce.isCancelled()) { if (!data.isZAPlayer(player)) {// JOIN if (l2.equalsIgnoreCase(Local.BASE_JOIN_STRING.getSetting())) { joinGame(sign, player, l3); } else if (l2.equalsIgnoreCase(Local.BASE_PERK_STRING.getSetting())) { player.sendMessage(ChatColor.GRAY + "This sign can be used in-game to purchase the " + l3 + " perk."); } else if (l2.equalsIgnoreCase(Local.BASE_ENCHANTMENT_STRING.getSetting())) { player.sendMessage(ChatColor.GRAY + "This sign can be used in-game to purchase the " + l3 + " enchantment for any weapon that behaves like a sword."); } else if (l2.equalsIgnoreCase(Local.BASE_WEAPON_STRING.getSetting())) { player.sendMessage(ChatColor.GRAY + "This sign can be used in-game to purchase the " + l3 + " weapon."); } else if (l2.equalsIgnoreCase(Local.BASE_PASSAGE_STRING.getSetting())) { player.sendMessage(ChatColor.GRAY + "This sign can be used in-game to open the closest passage for " + l3 + " points."); } } else if (data.isZAPlayer(player)) { ZAPlayer zap = data.getZAPlayer(player); int points = zap.getPoints(); if (l2.equalsIgnoreCase(Local.BASE_PERK_STRING.getSetting())) { givePerk(sign, player, zap, l3, points); } else if (l2.equalsIgnoreCase(Local.BASE_ENCHANTMENT_STRING.getSetting()) && BukkitUtility.isEnchantableLikeSwords(player.getItemInHand())) { giveEnchantment(sign, player, zap, l3, points); } else if (l2.equalsIgnoreCase(Local.BASE_WEAPON_STRING.getSetting())) { giveItem(sign, player, zap, l3, points); } else if (l2.equalsIgnoreCase(Local.BASE_PASSAGE_STRING.getSetting())) { buyPassage(sign, player, zap, l3, points); } player.updateInventory(); } } } } private void buyPassage(Sign sign, Player player, ZAPlayer zap, String l3, int points) { int cost = 1500; try { cost = Integer.parseInt(l3); } catch (Exception e) { Ablockalypse.getTracker().error("The sign at " + sign.getLocation().toString() + " does not have a cost value on line 4.", 0); player.sendMessage(ChatColor.RED + "That sign is incorrectly formatted.\nThe server has already been alerted."); return; } sign.setLine(3, " " + cost + " "); if (zap.getPoints() >= cost) { Passage a = getClosestPassage(sign.getBlock(), zap.getGame()); if (a != null) { if (!a.isOpened()) { a.open(); ZAEffect.POTION_BREAK.play(sign.getLocation()); zap.subtractPoints(cost); player.sendMessage(ChatColor.BOLD + "You have bought a passage for " + cost + " points."); return; } else { player.sendMessage(ChatColor.RED + "This passage has already been purchased!"); } } else { player.sendMessage(ChatColor.RED + "There is no passage close to this sign!"); } return; } else { player.sendMessage(ChatColor.RED + "You have " + zap.getPoints() + " / " + cost + " points to buy this."); return; } } /* Gets the closest game area to the given block. */ private Passage getClosestPassage(Block b, Game zag) { double distanceSquared = Double.MAX_VALUE; Location loc = b.getLocation(); Passage lp = null; for (Passage a : data.getObjectsOfType(Passage.class)) { if (a.getGame() == zag) { Location l = a.getPoint(1); double current = l.distanceSquared(loc); if (current < distanceSquared) { distanceSquared = current; lp = a; } } } if (lp != null) { return lp; } return null; } private void giveEnchantment(Sign sign, Player player, ZAPlayer zap, String l3, int points) { for (ZAEnchantment ench : ZAEnchantment.values()) { if (l3.equalsIgnoreCase(ench.getLabel())) { if (zap.getPoints() < ench.getCost()) { player.sendMessage(ChatColor.RED + "You have " + points + " / " + ench.getCost() + " points to buy this."); return; } ItemStack hand = player.getItemInHand(); player.getInventory().remove(hand); hand.addEnchantment(ench.getEnchantment(), 3); zap.subtractPoints(ench.getCost()); player.sendMessage(ChatColor.BOLD + "You have bought " + l3 + " for " + ench.getCost() + " points!"); ZAEffect.POTION_BREAK.play(sign.getLocation()); AblockalypseUtility.dropItemAtPlayer(sign.getLocation(), hand, player, 1, 1); return; } } } private void giveItem(Sign sign, Player player, ZAPlayer zap, String l3, int points) { Map<Integer, BuyableItemData> items = Ablockalypse.getExternal().getItemFileManager().getSignItemMap(); for (int id : items.keySet()) { BuyableItemData map = items.get(id); int cost = sign.getLine(3).isEmpty() ? map.getCost() : Integer.parseInt(sign.getLine(3)); if (l3.equalsIgnoreCase(map.getName()) && zap.getGame().getLevel() >= map.getRequiredLevel()) { if (points < cost) { player.sendMessage(ChatColor.RED + "You have " + points + " / " + cost + " points to buy this."); return; } AblockalypseUtility.dropItemAtPlayer(sign.getLocation(), map.toItemStack(), player, 1, 1); if (fireSale.contains(zap.getGame())) { cost = 10; } zap.subtractPoints(cost); player.sendMessage(ChatColor.BOLD + "You have bought " + l3 + " for " + cost + " points!"); ZAEffect.POTION_BREAK.play(sign.getLocation()); return; } } } private void givePerk(Sign sign, Player player, ZAPlayer zap, String l3, int points) { for (ZAPerk perk : ZAPerk.values()) { if (l3.equalsIgnoreCase(perk.getLabel()) && zap.getGame().getLevel() >= perk.getLevel()) { if (zap.getPoints() < perk.getCost()) { player.sendMessage(ChatColor.RED + "You have " + points + " / " + perk.getCost() + " points to buy this."); return; } perk.givePerk(zap); zap.subtractPoints(perk.getCost()); player.sendMessage(ChatColor.BOLD + "You have bought " + l3 + " for " + perk.getCost() + " points!"); ZAEffect.POTION_BREAK.play(sign.getLocation()); return; } } } private void joinGame(Sign sign, Player player, String l3) { if (player.hasPermission("za.create") && !data.isGame(l3)) { setupPlayerWithGame(l3, player); player.sendMessage(ChatColor.RED + "This game does not have any barriers. Ignoring..."); return; } else if (data.isGame(l3)) { setupPlayerWithGame(l3, player); ZAEffect.POTION_BREAK.play(sign.getLocation()); return; } else { player.sendMessage(ChatColor.RED + "That game does not exist!"); return; } } /* Checks for the game and player to create a new game instance and player instance. */ private void setupPlayerWithGame(String name, Player player) { boolean exists = data.gameExists(name); Game zag = data.getGame(name, true); ZAPlayer zap = data.getZAPlayer(player, name, true); if (zag.getMainframe() == null) { Location pLoc = player.getLocation(); zag.setMainframe(new Teleporter(zag, pLoc)); } if (!exists) { GameCreateEvent gce = new GameCreateEvent(zag, null, player); Bukkit.getServer().getPluginManager().callEvent(gce); if (!gce.isCancelled()) { zap.loadPlayerToGame(name, true); } else { zag.remove(true); } } else { zap.loadPlayerToGame(name, true); } } }