diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/Rank.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/Rank.java index 43fdbacdc..834c1eff4 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/Rank.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/Rank.java @@ -24,7 +24,8 @@ public enum Rank MODERATOR("Mod", "mod", ChatColor.GOLD, "Moderators enforce rules and provide help to \nanyone with questions or concerns. \n\nFor assistance, contact them using " + F.elem("/a ") + ".", 32, DyeColor.ORANGE), HELPER("Trainee", "train", ChatColor.GOLD, "Trainees are moderators-in-training. \nTheir duties include enforcing the rules and \nproviding help to anyone with questions or concerns. \n\nFor assistance, contact them using " + F.elem("/a ") + ".", 24, DyeColor.ORANGE), MAPLEAD("MapLead", "mapl", ChatColor.BLUE, "Map Leaders are leaders of the Mineplex Build Team. \nThey oversee the creation of new maps and manage Builders.", 25, DyeColor.BLUE), - MAPDEV("Builder", "mapd", ChatColor.BLUE, "Builders are members of the Mineplex Build Team. \nThey create many of the maps used across Mineplex.", 26, DyeColor.BLUE), + MAPPER("Mapper", "mapp", ChatColor.BLUE, "These senior staff members work closely with \nthe development and design teams to build new \nmaps for new and old content!", 100, DyeColor.BLUE), + MAPDEV("Builder", "mapd", ChatColor.BLUE, "These creative staff members help \nbuild maps for your favorite games!", 26, DyeColor.BLUE), MEDIA("Media", "media", ChatColor.BLUE, "The Media rank is given to talented artists who are\n endorsed to create content for Mineplex.", -1, DyeColor.BLUE), EVENT("Event", "evnt", ChatColor.WHITE, "A member of the official Mineplex Events team!", -1, DyeColor.WHITE), diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/entity/ClientArmorStand.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/entity/ClientArmorStand.java new file mode 100644 index 000000000..239f0af5c --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/entity/ClientArmorStand.java @@ -0,0 +1,1038 @@ +package mineplex.core.common.entity; + +import mineplex.core.common.util.UtilPlayer; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; +import org.bukkit.entity.*; +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionAttachment; +import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.plugin.Plugin; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.EulerAngle; +import org.bukkit.util.Vector; + +import java.util.*; + +public class ClientArmorStand implements ArmorStand +{ + + private static final int HAND = 0; + private static final int HELMET = 4; + private static final int CHESTPLATE = 3; + private static final int LEGGINGS = 2; + private static final int BOOTS = 1; + + public static ClientArmorStand spawn(Location location) + { + EntityArmorStand entityArmorStand = new EntityArmorStand(((CraftWorld) location.getWorld()).getHandle()); + entityArmorStand.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + ClientArmorStand clientArmorStand = new ClientArmorStand(entityArmorStand); + + for (Player other : clientArmorStand.getObservers()) + { + UtilPlayer.sendPacket(other, new PacketPlayOutSpawnEntityLiving(entityArmorStand)); + } + + return clientArmorStand; + } + + public static ClientArmorStand spawn(Location loc, Player... players) + { + EntityArmorStand entityArmorStand = new EntityArmorStand(((CraftWorld) loc.getWorld()).getHandle()); + entityArmorStand.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + ClientArmorStand clientArmorStand = new ClientArmorStand(entityArmorStand, players); + Packet packet = new PacketPlayOutSpawnEntityLiving(entityArmorStand); + + for (Player observer : players) + { + UtilPlayer.sendPacket(observer, packet); + } + + return clientArmorStand; + } + + private final EntityArmorStand _armorStand; + private ItemStack _itemInHand, _helmet, _chestplate, _leggings, _boots; + private boolean _visible; + private final DataWatcher _dataWatcher; + + private Player[] _observers; + + private ClientArmorStand(EntityArmorStand armorStand, Player... players) + { + _armorStand = armorStand; + _dataWatcher = armorStand.getDataWatcher(); + _observers = players; + } + + public EntityArmorStand getHandle() + { + return _armorStand; + } + + @Override + public ItemStack getItemInHand() + { + return _itemInHand; + } + + @Override + public void setItemInHand(ItemStack itemStack) + { + _itemInHand = itemStack; + sendPacket(new PacketPlayOutEntityEquipment(getEntityId(), HAND, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public ItemStack getHelmet() + { + return _helmet; + } + + @Override + public void setHelmet(ItemStack itemStack) + { + _helmet = itemStack; + sendPacket(new PacketPlayOutEntityEquipment(getEntityId(), HELMET, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public ItemStack getChestplate() + { + return _chestplate; + } + + @Override + public void setChestplate(ItemStack itemStack) + { + _chestplate = itemStack; + sendPacket(new PacketPlayOutEntityEquipment(getEntityId(), CHESTPLATE, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public ItemStack getLeggings() + { + return _leggings; + } + + @Override + public void setLeggings(ItemStack itemStack) + { + _leggings = itemStack; + sendPacket(new PacketPlayOutEntityEquipment(getEntityId(), LEGGINGS, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public ItemStack getBoots() + { + return _boots; + } + + @Override + public void setBoots(ItemStack itemStack) + { + _boots = itemStack; + sendPacket(new PacketPlayOutEntityEquipment(getEntityId(), BOOTS, CraftItemStack.asNMSCopy(itemStack))); + } + + @Override + public Location getEyeLocation() + { + return getLocation().add(0, getEyeHeight(), 0); + } + + @Override + public double getEyeHeight() + { + return 1.62; + } + + @Override + public double getEyeHeight(boolean sneaking) + { + return getEyeHeight(); + } + + @Override + public String getCustomName() + { + return _armorStand.getCustomName(); + } + + @Override + public Location getLocation() + { + return new Location(getWorld(), _armorStand.locX, _armorStand.locY, _armorStand.locZ); + } + + @Override + public boolean isVisible() + { + return _visible; + } + + @Override + public void setVisible(boolean visible) + { + _visible = visible; + _armorStand.setInvisible(!visible); + sendMetaPacket(); + } + + private void sendMetaPacket() + { + sendPacket(new PacketPlayOutEntityMetadata(getEntityId(), _dataWatcher, true), _observers); + } + + @Override + public Entity getPassenger() + { + return null; + } + + @Override + public Entity getVehicle() + { + return null; + } + + @Override + public org.bukkit.World getWorld() + { + return _armorStand.getWorld().getWorld(); + } + + @Override + public void remove() + { + sendPacket(new PacketPlayOutEntityDestroy(new int[]{_armorStand.getId()})); + } + + public void remove(Player... player) + { + sendPacket(new PacketPlayOutEntityDestroy(new int[]{_armorStand.getId()}), player); + } + + @Override + public void setCustomName(String arg0) + { + _armorStand.setCustomName(arg0); + sendMetaPacket(); + } + + @Override + public boolean setPassenger(Entity arg0) + { + return false; + } + + @Override + public boolean teleport(Location loc) + { + _armorStand.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); + sendPacket(new PacketPlayOutEntityTeleport(_armorStand)); + return false; + } + + @Override + public EulerAngle getBodyPose() + { + return null; + } + + @Override + public EulerAngle getHeadPose() + { + return fromNMS(_armorStand.headPose); + } + + @Override + public void setHeadPose(EulerAngle pose) + { + _armorStand.setHeadPose(toNMS(pose)); + sendMetaPacket(); + } + + @Override + public EulerAngle getLeftArmPose() + { + return null; + } + + @Override + public EulerAngle getLeftLegPose() + { + return null; + } + + @Override + public EulerAngle getRightArmPose() + { + return null; + } + + @Override + public EulerAngle getRightLegPose() + { + return null; + } + + @Override + public boolean hasArms() + { + return false; + } + + @Override + public boolean hasBasePlate() + { + return false; + } + + @Override + public boolean hasGravity() + { + return false; + } + + @Override + public boolean isMarker() + { + return false; + } + + @Override + public boolean isSmall() + { + return false; + } + + @Override + public void setArms(boolean arg0) + { + _armorStand.setArms(arg0); + sendMetaPacket(); + } + + @Override + public void setBasePlate(boolean arg0) + { + _armorStand.setBasePlate(arg0); + sendMetaPacket(); + } + + @Override + public void setBodyPose(EulerAngle arg0) + { + } + + @Override + public void setLeftArmPose(EulerAngle arg0) + { + } + + @Override + public void setLeftLegPose(EulerAngle arg0) + { + } + + @Override + public void setRightArmPose(EulerAngle arg0) + { + } + + @Override + public void setRightLegPose(EulerAngle arg0) + { + } + + @Override + public void setSmall(boolean arg0) + { + _armorStand.setSmall(arg0); + sendMetaPacket(); + } + + @Override + public int getEntityId() + { + return _armorStand.getId(); + } + + public Player[] getObservers() + { + return _observers; + } + + public void sendPacket(Packet packet) + { + sendPacket(packet, getObservers()); + } + + public void sendPacket(Packet packet, Collection observers) + { + for (Player player : observers) + { + UtilPlayer.sendPacket(player, packet); + } + } + + public void sendPacket(Packet packet, Player... observers) + { + for (Player player : observers) + { + UtilPlayer.sendPacket(player, packet); + } + } + + // Not needed + + @Override + public void setGravity(boolean b) + { + + } + + @Override + public void setMarker(boolean b) + { + + } + + @Override + public List getLineOfSight(HashSet hashSet, int i) + { + return null; + } + + @Override + public List getLineOfSight(Set set, int i) + { + return null; + } + + @Override + public Block getTargetBlock(HashSet hashSet, int i) + { + return null; + } + + @Override + public Block getTargetBlock(Set set, int i) + { + return null; + } + + @Override + public List getLastTwoTargetBlocks(HashSet hashSet, int i) + { + return null; + } + + @Override + public List getLastTwoTargetBlocks(Set set, int i) + { + return null; + } + + @Override + public Egg throwEgg() + { + return null; + } + + @Override + public Snowball throwSnowball() + { + return null; + } + + @Override + public Arrow shootArrow() + { + return null; + } + + @Override + public int getRemainingAir() + { + return 0; + } + + @Override + public void setRemainingAir(int i) + { + + } + + @Override + public int getMaximumAir() + { + return 0; + } + + @Override + public void setMaximumAir(int i) + { + + } + + @Override + public int getMaximumNoDamageTicks() + { + return 0; + } + + @Override + public void setMaximumNoDamageTicks(int i) + { + + } + + @Override + public double getLastDamage() + { + return 0; + } + + @Override + public void setLastDamage(double v) + { + + } + + @Override + public int getNoDamageTicks() + { + return 0; + } + + @Override + public void setNoDamageTicks(int i) + { + + } + + @Override + public Player getKiller() + { + return null; + } + + @Override + public boolean addPotionEffect(PotionEffect potionEffect) + { + return false; + } + + @Override + public boolean addPotionEffect(PotionEffect potionEffect, boolean b) + { + return false; + } + + @Override + public boolean addPotionEffects(Collection collection) + { + return false; + } + + @Override + public boolean hasPotionEffect(PotionEffectType potionEffectType) + { + return false; + } + + @Override + public void removePotionEffect(PotionEffectType potionEffectType) + { + + } + + @Override + public Collection getActivePotionEffects() + { + return null; + } + + @Override + public boolean hasLineOfSight(org.bukkit.entity.Entity entity) + { + return false; + } + + @Override + public boolean getRemoveWhenFarAway() + { + return false; + } + + @Override + public void setRemoveWhenFarAway(boolean b) + { + + } + + @Override + public EntityEquipment getEquipment() + { + return null; + } + + @Override + public void setCanPickupItems(boolean b) + { + + } + + @Override + public boolean getCanPickupItems() + { + return false; + } + + @Override + public boolean isLeashed() + { + return false; + } + + @Override + public org.bukkit.entity.Entity getLeashHolder() throws IllegalStateException + { + return null; + } + + @Override + public boolean setLeashHolder(org.bukkit.entity.Entity entity) + { + return false; + } + + @Override + public boolean shouldBreakLeash() + { + return false; + } + + @Override + public void setShouldBreakLeash(boolean b) + { + + } + + @Override + public boolean shouldPullWhileLeashed() + { + return false; + } + + @Override + public void setPullWhileLeashed(boolean b) + { + + } + + @Override + public boolean isVegetated() + { + return false; + } + + @Override + public void setVegetated(boolean b) + { + + } + + @Override + public boolean isGhost() + { + return false; + } + + @Override + public void setGhost(boolean b) + { + + } + + @Override + public void damage(double v) + { + + } + + @Override + public void damage(double v, org.bukkit.entity.Entity entity) + { + + } + + @Override + public double getHealth() + { + return 0; + } + + @Override + public void setHealth(double v) + { + + } + + @Override + public double getMaxHealth() + { + return 0; + } + + @Override + public void setMaxHealth(double v) + { + + } + + @Override + public void resetMaxHealth() + { + + } + + @Override + public Location getLocation(Location location) + { + return null; + } + + @Override + public void setVelocity(Vector vector) + { + + } + + @Override + public Vector getVelocity() + { + return null; + } + + @Override + public boolean isOnGround() + { + return false; + } + + @Override + public boolean teleport(Location location, TeleportCause teleportCause) + { + return false; + } + + @Override + public boolean teleport(org.bukkit.entity.Entity entity) + { + return false; + } + + @Override + public boolean teleport(org.bukkit.entity.Entity entity, TeleportCause teleportCause) + { + return false; + } + + @Override + public List getNearbyEntities(double v, double v1, double v2) + { + return null; + } + + @Override + public int getFireTicks() + { + return 0; + } + + @Override + public int getMaxFireTicks() + { + return 0; + } + + @Override + public void setFireTicks(int i) + { + + } + + @Override + public boolean isDead() + { + return false; + } + + @Override + public boolean isValid() + { + return false; + } + + @Override + public Server getServer() + { + return null; + } + + @Override + public boolean isEmpty() + { + return false; + } + + @Override + public boolean eject() + { + return false; + } + + @Override + public float getFallDistance() + { + return 0; + } + + @Override + public void setFallDistance(float v) + { + + } + + @Override + public void setLastDamageCause(EntityDamageEvent entityDamageEvent) + { + + } + + @Override + public EntityDamageEvent getLastDamageCause() + { + return null; + } + + @Override + public UUID getUniqueId() + { + return null; + } + + @Override + public int getTicksLived() + { + return 0; + } + + @Override + public void setTicksLived(int i) + { + + } + + @Override + public void playEffect(EntityEffect entityEffect) + { + + } + + @Override + public EntityType getType() + { + return null; + } + + @Override + public boolean isInsideVehicle() + { + return false; + } + + @Override + public boolean leaveVehicle() + { + return false; + } + + @Override + public void setCustomNameVisible(boolean b) + { + _armorStand.setCustomNameVisible(b); + } + + @Override + public boolean isCustomNameVisible() + { + return false; + } + + @Override + public Spigot spigot() + { + return null; + } + + @Override + public void sendMessage(String s) + { + + } + + @Override + public void sendMessage(String[] strings) + { + + } + + @Override + public String getName() + { + return null; + } + + @Override + public void setMetadata(String s, MetadataValue metadataValue) + { + + } + + @Override + public List getMetadata(String s) + { + return null; + } + + @Override + public boolean hasMetadata(String s) + { + return false; + } + + @Override + public void removeMetadata(String s, Plugin plugin) + { + + } + + @Override + public boolean isPermissionSet(String s) + { + return false; + } + + @Override + public boolean isPermissionSet(Permission permission) + { + return false; + } + + @Override + public boolean hasPermission(String s) + { + return false; + } + + @Override + public boolean hasPermission(Permission permission) + { + return false; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) + { + return null; + } + + @Override + public PermissionAttachment addAttachment(Plugin plugin, int i) + { + return null; + } + + @Override + public void removeAttachment(PermissionAttachment permissionAttachment) + { + + } + + @Override + public void recalculatePermissions() + { + + } + + @Override + public Set getEffectivePermissions() + { + return null; + } + + @Override + public boolean isOp() + { + return false; + } + + @Override + public void setOp(boolean b) + { + + } + + @Override + public T launchProjectile(Class aClass) + { + return null; + } + + @Override + public T launchProjectile(Class aClass, Vector vector) + { + return null; + } + + private static EulerAngle fromNMS(Vector3f old) + { + return new EulerAngle(Math.toRadians(old.getX()), Math.toRadians(old.getY()), Math.toRadians(old.getZ())); + } + + private static Vector3f toNMS(EulerAngle old) + { + return new Vector3f((float) Math.toDegrees(old.getX()), (float) Math.toDegrees(old.getY()), (float) Math.toDegrees(old.getZ())); + } + +} \ No newline at end of file diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java index 88dde15c3..f803154ce 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/skin/SkinData.java @@ -69,6 +69,16 @@ public class SkinData public final static SkinData SLENDERMAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTA0NzUyNzk4NTUsInByb2ZpbGVJZCI6IjlmY2FlZDhiMTRiNTRmN2ZhNjRjYjYwNDBlNzA1MjcyIiwicHJvZmlsZU5hbWUiOiJMQ2FzdHIxIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9hMWNkOTI5OTFmYTRjZGQ2MGVlZDNhZTM3ZmI5NWRmZjFkNWNkOGNiZmYwYWFjMzE4MmQ0ODU2NDU5NTIzYyJ9fX0=", "OVqWFLCekyZcdGli6kPBKNh8/VYPhKZGNqlAvSOKc3RLgh4pIkI6TDPr/Y+VQdhz1wZozARFYSeoDJJJ4nZTi7gi3rVPG2rL1ZnKo7so5hdT8caEzSTRmgwPKzo03ZhEEsW9AEJo9mpiUxGSJdBlgEb9UgodpYFW1IjRC09CcBUqzRWP8QGZTSFSN5x9emQ97DyiFmt0NFWubHCKHdb7CExhchPRtbahL3hOEzPY8/Y+Irl9OZjx7jONE7O/sYItCuZoXc3FaTgCV0riiXHCgH2eA54s5TQVWumtp3FU7VIcKR6pm/o61+GusvqhNgdFNk9XSHWMUyp+HNU0R8sConZQN/eaVx9laJmUUb4zNZ7hX/hLYV+r9LFU1NXOeIZWJPShD+bYfZgEorIpD+EAL4BHht/f5e6a1IZUDBWb001PFibby2t9WWjoDVKz4McbxZ2Xui7EHKFG1K3biPibhWx6fvnOeJ2xW6UDIZcD+TCXwlW/knkFt44Xpyv3oNHk3UNkyrQgghd6qkc3gZHxP8PQCNvKIyK1I+pHR6JMZvSStp7ZQRDpvsvIUyOJvq+7Bs7lFYs8hcJHMzEB+8PYlH2k7P7iLuA6ZYFUmvOW1LLq0+hvxK96ZdNEsJdmMkVVTZBRw7vsZ4GPbkdp2cMOFH2lHcQj80xKqVbd43IqFDA="); public final static SkinData BOB_ROSS = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTU2NjEyOTc2NTcsInByb2ZpbGVJZCI6IjdkYTJhYjNhOTNjYTQ4ZWU4MzA0OGFmYzNiODBlNjhlIiwicHJvZmlsZU5hbWUiOiJHb2xkYXBmZWwiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzVhNzZhN2NlMzZlZGRiYmZhNWMzMmJhZmVhYmUyNmQ3ZWJlNWRlOTBkNzYyYzJmNWY3OTQ1ZTQ1ODUxOTU2ZDYifX19", "b7pUQSZ1UkMZJNSqdaBPGWfm+rfvFkEh58pBvYTG2RBPwVju1kKinb1LfsyYhFKlyPvL1jfqi30udmb0302QvE0SKg7p3txxULa3Hr94+eCJWFxrOxUNorRT9E+TurJxH6jimu6KW1p6goPn77/kgNaWb9xn3+E84+vH0z9ETjgc5G0aYLT+cSzThUorhvOQ7DRLfRgSWiFxfm3Er0g+waLfDEeNNAd6OJ5k3X+kgM/+V6QTIFofnZZ6NdZZInTARAVol2H0pRfQfAuVYfJyVyvA0uF+ZX+wlMuBTG1MeyWjZgI1iUKmGaQADXsAV796kT+Z+tAXpbRYYYZnxil5jx5P4druiHvaQfV2KK3lbKm2uH9M3SZr5d57C3V24BKRRWGS4C9INzgO8ORIIomes7kp0gECS4MnSMI6hcl0JsXVlaAy88BgmT/PKxM+3q4PCQE1N9fTCuhoil7vVYIU3uBXwFUE7NTAOUdBee+3TtMstIu2WP8rtEZBVpGH9CmomaLTCzPZSdXGY31goOFXSRYMNi8j4ykuBgP0qJqimipWH0rBF1bMdHqMu359h62tTLRKipHWXPxj4N8c/n1CVPYjuXH9X3f1HAU4DnET+v93Vb/uzbx8rXFrz6jLPwAjSlJ8Th3VE+4ey/ZBHWPB+SuHetN+e0r/LYxiqwwlnwI="); + public static final SkinData HATTORI = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjEyMTczMDgsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS83MjczMTBiMzlhMTIzOWI3ZTI4Y2JjNTkzMWY1MzlkNGVlNmQxOTc3ODhjNWI1YTY3YWY1NDJlYzk0MmZkMyJ9fX0=", "aHfFqPOZmcQkUqFPjVa27h27k5gyvkZMCOyIaIdIZfqVDg/69/hakkDQazvKg/U8KTlYaDSRyOp9ZD5qOUSCPvRtRDMhuX/Tn68KD9BdW5jYKsXo0puOa7IJDKAE47z7YQ8AvfOtxuOAg6S0ihjYEQqRA56UQ+gPbkd+pxpMxvXoLyAx7IEIKWmlkibG/rmaX8J7OEgq8Wi9s6BhtPVNMaLoznzdzOiiYkcza/zEG5zMXnj/hFHHUpWrYff0Oj7/SUB+krLsiMficASzzs/9HZq81V0ketqUhJYX66HL8F5fQniP8kYu9LbNNcVJmtlER03QaEqP/H8udemlVskFkOYLkTmhxfSetL46N+ZVf0Sxp2xYcFOH3djH/Q26IIXtzEqVyUW5Gun/ZJp8B8zYMOXbXSmaALAYPoX9cs91ZilNX/W7zn7b5Kb9kUBGt58eUpKoXjgK7rSvmH0X2JOZGFVji5QKzp/eOQAqMhkBOU8sEm9AT6mfZjjlyIDOZxSX6hjEJXRVVzFFlzTiRPTcAtaHWRnlRFywsDDSgVBGvQMPNMNa6CFeo0ajnhmfHWa4Ga77kpfQ75PzOoJ/j6Z/2sSIHfQFWE6INAGAyypX/x0Fd/AH6SmYfilnX6lhtd7OsDlxS01QGoRLPBh/ol+wY6rHSM1N6Qta0ulpQZLYIms="); + public static final SkinData ANATH = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0Njg4NjM4MTYsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS81NGI5NGQ4NzE5ZWFhYjc0YjVhMzhjN2Q5NDliM2FkMmIyYzA0ODIxZGY4OWM1ZDA0YjY5ZjNjZmExYmJhNjUifX19", "IKlnXzQ2k57XyTHge5V2ttnV1AqbRKrV0JktZS4+nLXx+ROM77/HRuf3/bYTqg48SB8npXy+c6nLYTCY1fTZOl3t2puS6BpZMBXuTV//A0OMQ1pJKzDb8vW6CwPYw2Nu6o0QX3J/FeUIaBj16GZAPxXOtSekkeOw9qsdh57GyqSmzODlEA/7CnJWqX2Ani5DACzo6j5rzfsz2qRgOzVlnbVlVzpXicRuYYLxKvT4nMS+B3HpQdsyFKAx8nTO/GmCHDzW97jck6w/VDlW9x+J39tPDEaKPLbDz1YV59yJt6hjNAcnwgbf3KvHSAbGZNLqRegq/Rk20ZI2J5GYT5ipiyf+p8rHfkRTxIsVCMyVecnSKaz59YQ7AleiWVGzYHDETU702UyigAZFHGHQ/0Kj9UyyZ4ew228FQuGo7iGY4dS/PKq40d1v3fq+czwBhcXR+Msi1Zqg/4dTh+QwwwWsIS3CKtOInpJgZ3U/tkn4STB3o+oKBbmBWvpJk8SrA6DVKKJMjHQig+67hXKSbdcRUWAoGc/iuRhRXgILkC99Ot4PHohEbwbEW8MsKxm49OFqzP4zptaUaiQpMK4YCxENhLrI7X+w51tt2XTjroIHu4oLYS4pG16ZnhUmd/RFg8Ar7mBVOv/2lUtOO5aMAv88CpyD+XXNcCQB4G5pv4c0F14="); + public static final SkinData DEVON = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0Njk0NDE1MDYsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS85N2FkNjY1MjFmNzNjOWFmYzE4MzliZGExYzE5ZDNkMjg3YjNmMjRmY2EwZTBlMTE1NzhiOTE0ZTNiNWIwZDIifX19", "BNIc7N3SGIXOEUKFe3hrQp4YmniPxkiL5aKAUNkTmYqbygAQlrCCrwJTuK6JrzkWmD5AzMSzMDKkmoMWOikgulhSmDyC88lQz/LQH3co7WldPHaPL6kk27ZirmIIZEm5WKcvWhQ7ChNWQd2KsZuFqxZSdLSQmsbujF9vpuVbhlU4hajsUwbdiOJRZ18fOAFoJYq/g3RlvqC9VtAA/IAAN7jIpXf9Pn5+vjLqN+AdKm27YknCpqMtBfkYaIhMrpTBe2gP+o50TmH0xm0IZPCS+ORYNGwFdCsg6DzEU7a0rtcUdcZgdInc09mS8tMY9eeMAISYYq5MpyliHQ/areGKk0RJEYg7muc9r/N6vBUpxZtZH8BioDj2dNj4JOoH/58cwU3+hv/Woykc9o5NUPyz0nndiOtTUp1SaDXleKyHryoYnIkPyaDPyuA7qTbIKZQHxyAdrRsnknb0PYku6T8RA4kWNK2jlOH+R9D4eiKFcbLRU2Zl6L57lJTZFFI6GUvzDsyD/vBb59gjvXYzRmvguX9CHUc1aLDeUKhV8NFXeaonoYM9VPIUBQRWNdMery9OlBiQvg4VXy1w2yKLvlHRhJZJpDm/IDdsfg27o8+BUOZ0xHF9iXPBDkOiLXXZ02X4IonLcopVNImCMRZJ1dKHwgu9qnFqVTEKH4mwXUz2Zq8="); + public static final SkinData DANA = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjkyMzgxMDAsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9hOWRhYTg5OGVkN2E0N2YyOGFkMjVmNjk5Y2Y4MzQyODFmMTVkZTY5OWM1MWVhMTRkOWRlYzVhM2VlNzY1MiJ9fX0=", "KUI3h0MDUNWQ3avjozkw0KnZf1UAMkRHzRKY9yGS/iUh9EMmDbfLcRfBhUvR5Dd6//75Yw2tElBrvPx+VqfJk0LqMACQc71n0lDY1NzqnXbpf6vNGyuhyumjhMSjJTG3BJ8Qtdd1yCsPK2x5ym+cGPS1FevJj4Vcu6rxg9HXZokgfjD11NXEwulFuPIiWHpJlnd8NlBw4a3txlrVwDnaHo7GqYSJeM1uOCrdICdpThSA2N2mOUEmOHvH9rHUhQvkKHipbsQMIxIX4oiXDWeK6P/GtT+Iv0DIeJfQdDkhDiIG5/zUyxmpC2mma1FQIsFsQOaJfgYZLfcOXGdhwlL/OcZ9ULBIKhgSx7Ozwzsc+JKonqlaBOuaietq5z/XvMClgFG9U2a1LXc5BIgaN/ClsO0uTksuoA8H0SDx9k3EmOjaPdrJOsQ/fgWQSkWN2XniLLFiEtSOEOI58vw6ORVXDgjbP+TqD0b6/d10z0jUzS2FD7AO51LHzTw+BjqoyVef4fszNNSqMi5QEgfBl++EAolZBAMHgN7hq6k52ry2LPlO5L8sm6NoZ4DrLyrx1oFNtXZZgYvNVy7rtEpIDdQczwAZkJFV0fuz8tRH3CkW/roA5HbfX3Fv19mQoteoemrSUrOwLlQsyVPxsFsn8uX94Cw88Q5KgBCGmGY2vpXHuiI="); + public static final SkinData BARDOLF = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjkxMTE4NjEsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84MjUxNjZmNzc0ZjcyNmZmMDE3NTQ3OTk0NDc0MGYxNjRmMTZmYmI2M2I3NGI3NmNmNzk0NDMxZGZkNzUyIn19fQ==", "W8TO4M/IQ4rQ91627EaudboKwR8TuKTp5mAYOCyOJLCD0vyyEJmnZFy1Hv9HlXKiXsEm9iC36+cmQ8JfSE0JlIfU2vRH5qbXUL4HUHZi20SHVA5YKM2ztxI9uouc14ctv8pxlhT/huKxYNgB/eJR+ckT1gyc78RBoJj5YLwUTsptO87KE/vFg9hbHVo5lVSdk//jhfDsMRyf0RXp/wKZ1KGxaRA5hWQUc86mLJTiQU1EBVh3Lfb2zUq2w/gpLCoxdwiX8KnNuX1a1iC8pFCZm4VJ20yvNPaIgzFYDFfNQO6Vwv9fcLsdxVH819cEkjxg5do9MpZBj1OVmaWnTmQ4w4r3iKFzL6LMae4eOEyA/vJ8e7mbWUNrxM3+EPUPlxpG/NKr2VsR2ihIIF9GTduBZa2ayj7BJAkL9UK5PEGh/UxG6jf0YS7RjQ9ROaRgmTLMFsOVnQlFlp2UFRTe+heh/woD8/QSpd9MELdWFzeKRAlo7+hvo5AfWyjBI/3e9PIJfCXp+nF3Z92HKoR5V0m9QoYu2WGzbkhU49DJF7n+Bnd3ur0qefHFVl3USdVU2DJLcdcKU+Qn5G6E8NSy/3TVkjDg6u/o38b203b0tUBZNftAYYmCCpx/HVMEoNC03orIBPrwGYD6g//RC1TZ2ZxkLDU4QxeaM6neWq1xryXbvS4="); + public static final SkinData BARDOLF_WEREWOLF = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjkxODMxOTAsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9kNzc0ZGY3OWU1OGFiNDQ5OGQ2YzY3ZTdlMjY2NWFjZmE2OTViOWNjOWNkZTE1MmQ3ZTVlM2NjMTUyNzM5In19fQ==", "nqc7IdRVa2RF2SZXRli/HVhw7q5NfY7rnZFWbDyzjQ90Y/H6NWhb+9gwDDdnh7B1WolyptyUnukzTOQmrAcSecVO5vblhCTYY8PEOfcwUKznjpCmL/BgXdzBoYJHs43HFbtvzt3yhshcQ8Wvh7mtdmNu0MEYKbIX7lTqcfSoUbDk+A1PZDINuOF5RM8disGCrkq6WTdLij+k7pd3e7MJhtf8vJbtSoo5TjfzyzJyFvEvZqa+3lxobbPA9Z4cels0DVWVU8I/FEJhB29aSVXDVAZps3vWUr1sLMM9+PRaZdxHPZfNHx6q9R3oHXgjAlqzJwkljtJGExyOV+vOHEUuxrytdwMcW0XGjalukHVJ1A9DCgNMZqAXEbfYKk+BsN2BzOwT/+dtGfsOU+Rq7Kzp1/iit9saQy1QEG8Bynj6A2Vmg9XZsvbYsXZXsE+qNG6TOADEV0yrS9icEhLhOnO0re/+wE4Zsd5WDF51e87+ugvoH3iM4zrzvaWQb6McgxD/wlYlJyVHD+2f5VYCIw2yacNXp6LaZuXpfQyyDCqpHAosTYNLxWwjinl05C/TprQw+sZoLHFCGbVFQjTPEkDhQzG73PHecnO5Px3USBVleDoTb1kZfq6J2wJ1B1/7MTBW21Din3j2DmmuAVUNJYe6kifaNOhY1ghG2WVRNdIf1b4="); + public static final SkinData LARISSA = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjE0MTUxMzQsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jYThjNDRhOWVmZTY3NzExMDYzMjM5ODEwNDRmOTdjYmM1OWJmZmRlOGI1ODdlMGQzMWE4N2ViMDhhMmExZiJ9fX0=", "Lyac51CrnMK/CI2dWgGQLowAm/ZnQMpf0Ict/gqVrUgJVlGWDIVG77Rd1JyMQDEeESvTmoyivH+usiO0ePW95qjisqT3R43YEmLi85CqctGYqLKeSYpGYwYRz8Euw57LwJAALKOMLhVc2s4h2Or9nTecunG8KSmkCuZc4H1qh3frU+ltuV4HLqgdFUULbIHTggyvqiINov2tBqkkXeEjT7sOcTJCJNgNYU2O7//qg5kJmhso2CKHlRLpmy9LsaUK/Z+BzUmoRbwQgSwr3mz7dFAdlVWWKvKNcgX3nt1et0DIig3JKYmrnQX2Fprg+kWcr3nuizzLgjVwAlADC48P3DN0s/VBty2AYoWie16VNPIM+CV4BF2JRQ34GxZ8XceXbCKURrOjoCBgLGHvIhRW35eicoh26xp3/mwLvk5anPi5StJ/qEuzWJALeWcNbLsnt21m2MZp9h/MxaY6ftWOTzjTr5CYVd/teJyscMnGK4+lcV1dlt12lhbDMv6I+iz8iG9NIzuW5OvGkax90dA/Gq+Cd9FXVThPY4ufxWttHcTqgPB64GfMn6rywRm1B0eO1pJpYc/KlJZlW/PuaO8L1assyJs5KkOypBSy3zc6TO6pzgeOZv+VpQfA/UWpogv6ofmTpgdtwpjLFGSzIKTDXvF6FftALKVlYypG0fYbssA="); + public static final SkinData ROWENA = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0Njk1MTcxOTgsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jNDY1OGExODY4YzNhNjhhZWVhZmZkOTUxZDQyYmZkN2QxYTRjNGZjNDJjZDI2YTlmYzhkNTNmOTkxMTM1ZCJ9fX0=", "OqXMyH9SMmQ/Pwmb21In29YnCxbsN6yqUxfudN6KNgDwRUK6y072XhW6TIoTh9JQLAUKftpeVB53tk0LxHIxnsuBMrIHvETPDQFysIc/6xq3ABogs+zqFzcp5jk6S73HiD78JxLq5pzfUzhgDPMPuZP5Q/u2q1rYbe6B9lVEJ5sUcxBLUTossgucoR4qXYAlWVQdHRhq85Ol8a+OU7ruw3HackNGto6wt6u2MigCtiHVTt9XhJ/AJE4ScodQ3XwW4L6urpl/lV2OMCsr3mCjjjEz2EMhDbCWxrAorQ9aPpMbDkHBS+4TC1tbMGUlKhj5n+EZBYVaeLr4NGPACPSdT35p/2Zra49+DXn9Xn+681yNEB0ghTdsnsgwXg76+HVPHPqRHQMuTBQGQyGZaaTX/zE0tFjH+osMElLdb8dmz3dC7kQA4A13B2phj3YbMSF1FoU4GvnPKIQn6JIuEd6hd+pRLUW7Y+mgYIHHX1FT0ihrXAyVO6lQQ6rs92gSQr7sxC7tnhPSMFcmh7OcJYcbRpn97GMubthPLanOhVy7CKqjmwIkEVtYgP28idigKwNJ+sJuUONrOu7nMKl1UTD5EEapOacc/np6UhdSw8yW+LnWD/x9ueYz9ksnyRrJgcOa41izo/WCbjPK/j3JVezr9Q3x1yveWuFmdl7CGYdXngw="); + public static final SkinData BIFF = new SkinData("eyJ0aW1lc3RhbXAiOjE0OTc0NjEzMDQzNjYsInByb2ZpbGVJZCI6Ijg1MmE4YWNmNzMzNzQwZDc5OWVjYjA4ZmQ5OTY1MGI1IiwicHJvZmlsZU5hbWUiOiJLaW5nQ3JhenlfIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9mOWMyMTE3ZDY0ZWE0ZmUxMWZiY2NhZmE2YzU5YzhlZjY3NDVkZjVkMTZjM2QwMmI4NmI2OTlmZWJjNTA0OGI1In19fQ==", "mJMpEvQ4A02z0S/chgLm5bKrrrd+zmp7A0012AB7b3KlyIHoLKEDDz+ZJgJtvN6skOqed3P+yNVqkxitugXaZZP8Af9J+/TseHn+vOy6CTK5tykRSY3Zb8Zmw1kn36v/SARAVtDIHD53yuPgJayYSAbVB7aknj1Q8XBQGUmZRMRxWWxeD7rQTOwgRYI4YJeKFf4UL9i6zxvOJuHsOAouJ7scu7VohG8vgR77Js/Z8rSu8/aSG+O9AQdzP6h9ixYNFkkQOHm7DseK/5tsWKHM4FYBgjIDKt3ApQokSbhThzGB55BA1qjXZkfCoOb13y1nOMC8WoIL6Ees1qzxG3VloGx2WAZLh+Q+/irwrFDMxk1zeU5fIRuj1c/UIM2HKdxxWgoRdrZ8ww/Jrll6maiOBx7geMn/0aOUbJ2U7gkTif6RG6YNS5YN9ZQDLh72l/akJMxF3SlmuAPmLs2kBghQ6eD2YQKuxWR/Hf1yS1YXtogFVNsGnzC1nda7F48EGL3zI+kCajbDlAGQ32aRt0btbEQ+Gj575kir3Aa53qiZ0YOIYQlhgZdOsTN2NE2s8uuy/15Rgc6K3ydgEmSZfdqyMyW0Dy7pE5TfVL8DumKRVRXdOceT5WfnW7MyqSmdorP5ab1fw2wLOnAVzhJmW8oXXNSs77WJ1/PURclxOWB4IF8="); + // Comments this out for now, so it doesn't load the player profile // A better way to do this would check for the properties when getting the skull or the skin // Might change on the next version diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilParticle.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilParticle.java index 7b85b4971..a87bb2565 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilParticle.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilParticle.java @@ -258,11 +258,9 @@ public class UtilParticle } } - PacketPlayOutWorldParticles packet = new PacketPlayOutWorldParticles(particleType.particle, displayFar, + return new PacketPlayOutWorldParticles(particleType.particle, displayFar, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, count, details); - - return packet; } public static void PlayParticle(ParticleType type, Location location, float offsetX, float offsetY, diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/particles/effects/LineParticle.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/particles/effects/LineParticle.java index 5eccc50b9..2842cdd75 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/particles/effects/LineParticle.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/particles/effects/LineParticle.java @@ -31,10 +31,16 @@ public class LineParticle private double _maxRange; private Set _ignoredTypes; + private boolean _ignoreAllBlocks; private ParticleType _particleType; private Player[] _toDisplay; + public LineParticle(Location start, Vector direction, double incrementedRange, double maxRange, ParticleType particleType, Player... toDisplay) + { + this(start, null, direction, incrementedRange, maxRange, null, particleType, toDisplay); + } + public LineParticle(Location start, Vector direction, double incrementedRange, double maxRange, Set ignoredTypes, ParticleType particleType, Player... toDisplay) { this(start, null, direction, incrementedRange, maxRange, ignoredTypes, particleType, toDisplay); @@ -73,7 +79,7 @@ public class LineParticle Location newTarget = _start.clone().add(new Vector(0, 0.2, 0)).add(_direction.clone().multiply(_curRange)); _lastLocation = newTarget; - if (!(UtilBlock.airFoliage(newTarget.getBlock()) || UtilBlock.airFoliage(newTarget.getBlock().getRelative(BlockFace.UP)))) + if (!_ignoreAllBlocks && (!(UtilBlock.airFoliage(newTarget.getBlock()) || UtilBlock.airFoliage(newTarget.getBlock().getRelative(BlockFace.UP))))) { if (_ignoredTypes == null || !_ignoredTypes.contains(newTarget.getBlock().getType())) { @@ -87,7 +93,12 @@ public class LineParticle return done; } - + + public void setIgnoreAllBlocks(boolean b) + { + _ignoreAllBlocks = b; + } + public Location getLastLocation() { return _lastLocation; diff --git a/Plugins/Mineplex.Core/pom.xml b/Plugins/Mineplex.Core/pom.xml index a59a05b9b..50bfe79f3 100644 --- a/Plugins/Mineplex.Core/pom.xml +++ b/Plugins/Mineplex.Core/pom.xml @@ -32,6 +32,11 @@ mineplex-serverdata ${project.version} + + ${project.groupId} + mineplex-questmanager + ${project.version} + org.apache.commons commons-dbcp2 diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java index 94b8c35f7..30d4ae905 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java @@ -31,6 +31,7 @@ import com.google.common.collect.Sets; import com.google.gson.Gson; import mineplex.cache.player.PlayerCache; +import mineplex.cache.player.PlayerInfo; import mineplex.core.MiniPlugin; import mineplex.core.account.command.TestRank; import mineplex.core.account.command.UpdateRank; @@ -260,6 +261,53 @@ public class CoreClientManager extends MiniPlugin loadClientByName(playerName, client -> runnable.run()); } + public void loadClientByUUID(UUID uuid, Consumer loadedClient) + { + runAsync(() -> + { + AtomicReference loaded = new AtomicReference<>(); + try + { + Gson gson = new Gson(); + + String response = _repository.getClientByUUID(uuid); + + ClientToken token = gson.fromJson(response, ClientToken.class); + if (token.Name == null || token.Rank == null) + { + loaded.set(null); + return; + } + + CoreClient client = Add(token.Name, uuid); + client.SetRank(Rank.valueOf(token.Rank), false); + client.setAccountId(_repository.login(_loginProcessors, uuid, client.getName())); + + Bukkit.getServer().getPluginManager().callEvent(new ClientWebResponseEvent(response, uuid)); + + if (client.getAccountId() > 0) + { + PlayerInfo playerInfo = PlayerCache.getInstance().getPlayer(uuid); + + if (playerInfo != null) + { + PlayerCache.getInstance().updateAccountId(uuid, client.getAccountId()); + } + } + + loaded.set(client); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + finally + { + UtilTasks.onMainThread(() -> loadedClient.accept(loaded.get())).run(); + } + }); + } + public void loadClientByName(String playerName, Consumer loadedClient) { runAsync(() -> diff --git a/Plugins/Mineplex.Core/src/mineplex/core/achievement/Achievement.java b/Plugins/Mineplex.Core/src/mineplex/core/achievement/Achievement.java index 1d1dd47c4..90872f27c 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/achievement/Achievement.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/achievement/Achievement.java @@ -1201,7 +1201,31 @@ public enum Achievement new String[]{"Skyfall.SupplyDropsOpened"}, new String[]{"Be the first to open 20 Supply Drops"}, new int[]{20}, - AchievementCategory.SKYFALL); + AchievementCategory.SKYFALL), + + GEM_HUNTERS_KILLS("Gem Killer", 5000, + new String[]{"Gem Hunters.Kills"}, + new String[]{"+1 for each kill"}, + new int[]{10,25,50,100,1000}, + AchievementCategory.GEM_HUNTERS), + + GEM_HUNTERS_GEMS_EARNED("Gem Millionaire", 5000, + new String[]{"Gem Hunters.GemsEarned"}, + new String[]{"+1 for each Gem cashed out"}, + new int[]{1000,2500,5000,10000,100000}, + AchievementCategory.GEM_HUNTERS), + + GEM_HUNTERS_QUESTS("Quest Complete", 5000, + new String[]{"Gem Hunters.QuestsCompleted"}, + new String[]{"+1 for each quest completed"}, + new int[]{10,25,50,100,1000}, + AchievementCategory.GEM_HUNTERS), + + GEM_HUNTERS_CHESTS_OPENED("Loot Get!", 5000, + new String[]{"Gem Hunters.ChestsOpened"}, + new String[]{"+1 for each chest opened"}, + new int[]{50,100,200,400,1000}, + AchievementCategory.GEM_HUNTERS); private String _name; private String[] _desc; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementCategory.java b/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementCategory.java index 3a2d752df..885bf7939 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementCategory.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/achievement/AchievementCategory.java @@ -213,7 +213,15 @@ public enum AchievementCategory StatDisplay.fromGame("Wins", GameDisplay.SkyfallTeams, "Wins"), StatDisplay.fromGame("Games Played", GameDisplay.SkyfallTeams, "Wins", "Losses"), StatDisplay.fromGame("Kills", GameDisplay.SkyfallTeams, "Kills"), StatDisplay.fromGame("Deaths", GameDisplay.SkyfallTeams, "Deaths"), StatDisplay.fromGame("Gems Earned", GameDisplay.SkyfallTeams, "GemsEarned"), null, StatDisplay.fromGame("Booster Rings", GameDisplay.SkyfallTeams, "Rings")}, - Material.DIAMOND_BOOTS, 0, GameCategory.SURVIVAL, null, false, GameDisplay.Skyfall.getGameId(), GameDisplay.SkyfallTeams.getGameId()); + Material.DIAMOND_BOOTS, 0, GameCategory.SURVIVAL, null, false, GameDisplay.Skyfall.getGameId(), GameDisplay.SkyfallTeams.getGameId()), + + GEM_HUNTERS("Gem Hunters", null, + new StatDisplay[] {StatDisplay.KILLS, StatDisplay.GEMS_EARNED, StatDisplay.fromGame("Quests Completed", GameDisplay.GemHunters, "QuestsCompleted"), StatDisplay.fromGame("Chests Opened", GameDisplay.GemHunters, "ChestsOpened")}, + Material.EMERALD, 0, GameCategory.SURVIVAL, null, false, GameDisplay.GemHunters.getGameId()), + + MOBA("Heroes of GWEN", null, + new StatDisplay[] {StatDisplay.WINS, StatDisplay.GAMES_PLAYED, StatDisplay.GEMS_EARNED, null, StatDisplay.fromGame("Gold Earned", GameDisplay.MOBA, "GoldEarned")}, + Material.PRISMARINE_SHARD, 0, GameCategory.CLASSICS, null, false, GameDisplay.MOBA.getGameId()); private String _name; private String[] _statsToPull; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/achievement/ui/page/AchievementMainPage.java b/Plugins/Mineplex.Core/src/mineplex/core/achievement/ui/page/AchievementMainPage.java index 0ff566c82..bab3f5efd 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/achievement/ui/page/AchievementMainPage.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/achievement/ui/page/AchievementMainPage.java @@ -51,7 +51,7 @@ public class AchievementMainPage extends ShopPageBase pageLayout = new ItemLayout( - "XXOXOXOXO", + "OXOXOXOXO", "OXOXOXOXO", "OXOXOXOXO", "OXOXOXOXO", diff --git a/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java b/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java index ca0f67e27..bf384c4c8 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/beta/BetaWhitelist.java @@ -55,8 +55,8 @@ public class BetaWhitelist extends MiniPlugin { Player player = event.getPlayer(); Rank rank = _clientManager.Get(player).GetRank(true); - if ((rank != Rank.MAPDEV && rank != Rank.MAPLEAD && rank.has(Rank.ETERNAL) // If this player is Eternal+ (and not a builder), - || _powerPlayClubRepository.getCachedData(player).isSubscribed()) // a PPC subscriber, + if (rank.has(Rank.TITAN) // If this player is Titan+ + || _powerPlayClubRepository.getCachedData(player).isSubscribed() // a PPC subscriber, || EXTRA_PLAYERS.contains(player.getUniqueId())) // or explicitly whitelisted, { return; // allow them in diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java index 06f1d69b4..2bdd967f5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/BonusManager.java @@ -941,12 +941,7 @@ public class BonusManager extends MiniClientPlugin implements I if (!_enabled) return; - Entity entity = event.getRightClicked(); - if (entity.equals(_carlNpc.getEntity())) - { - updateDailyStreak(event.getPlayer()); - new BonusGui(_plugin, event.getPlayer(), this, _rewardManager, _facebookManager, _youtubeManager, _thankManager, _playWireManager).openInventory(); - } + attemptOpenCarlGUI(event.getPlayer(), event.getRightClicked()); } @EventHandler @@ -957,12 +952,22 @@ public class BonusManager extends MiniClientPlugin implements I if (event.getDamager() instanceof Player) { - Player player = (Player) event.getDamager(); - if (event.getEntity().equals(_carlNpc.getEntity())) - { - updateDailyStreak(player); - new BonusGui(_plugin, player, this, _rewardManager, _facebookManager, _youtubeManager, _thankManager, _playWireManager).openInventory(); - } + attemptOpenCarlGUI((Player) event.getDamager(), event.getEntity()); + } + } + + private void attemptOpenCarlGUI(Player player, Entity entity) + { + if (_carlNpc == null || _carlNpc.getEntity() == null) + { + System.err.println("Carl is missing! (carlNpc=" + _carlNpc + ")"); + return; + } + + if (entity.equals(_carlNpc.getEntity())) + { + updateDailyStreak(player); + new BonusGui(_plugin, player, this, _rewardManager, _facebookManager, _youtubeManager, _thankManager, _playWireManager).openInventory(); } } @@ -1261,4 +1266,9 @@ public class BonusManager extends MiniClientPlugin implements I { _carlLocation = carlLocation; } + + public Npc getCarl() + { + return _carlNpc; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java index d1282cc18..9af639e86 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/bonuses/gui/buttons/PowerPlayClubButton.java @@ -127,7 +127,7 @@ public class PowerPlayClubButton implements GuiItem itemName = C.cRedB + "Power Play Club"; lore.add(C.cYellow + YearMonth.now().getMonth().getDisplayName(TextStyle.FULL, Locale.US) + "'s Cosmetic"); - lore.add(C.cWhite + " " + PowerPlayClubRewards.rewards().get(YearMonth.now()).getPrizeName()); + lore.add(C.cWhite + " " + PowerPlayClubRewards.getReward(YearMonth.now()).getPrizeName()); lore.add(" "); lore.addAll(buildOtherRewardsLore(1)); lore.add(C.cRed + "Get Power Play Club months at"); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BlockProgressBar.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BlockProgressBar.java deleted file mode 100644 index d18cc45ec..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BlockProgressBar.java +++ /dev/null @@ -1,57 +0,0 @@ -package mineplex.core.brawl.fountain; - -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; - -/** - * This class handled filling a vertical area with a specific block based off a percent - * - * @author Shaun Bennett - */ -public class BlockProgressBar -{ - // Starting block for the block fill - private final Block _startBlock; - // Direction the blockfill takes place in - private final BlockFace _direction; - // Blocks in order from lowest to highes - private final Block[] _blocks; - // Material used to fill the blocks - private final Material _material; - - public BlockProgressBar(Block startBlock, Material material, BlockFace direction) - { - _startBlock = startBlock; - _material = material; - _direction = direction; - - // Add blocks to array - int i; - Block curr; - Block[] blocks = new Block[100]; // max of 100 to prevent blocking - for (i = 0, curr = startBlock; (curr.getType() == Material.AIR || curr.getType() == material) && i < blocks.length; i++) - { - blocks[i] = curr; - curr = curr.getRelative(direction); - } - - _blocks = new Block[i]; - System.arraycopy(blocks, 0, _blocks, 0, i); - } - - // Update the blockfill based on fill percent - public void update(double percent) - { - double percentPerBlock = 1D / _blocks.length; - double check = 0; - - for (int i = 0; i < _blocks.length; i++) - { - _blocks[i].setType(percent > check ? _material : Material.AIR); - - check += percentPerBlock; - } - } - -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BrawlShopProvider.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BrawlShopProvider.java deleted file mode 100644 index 89635b062..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/BrawlShopProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package mineplex.core.brawl.fountain; - -import mineplex.core.shop.ShopBase; - -/** - * @author Shaun Bennett - */ -public interface BrawlShopProvider -{ - public ShopBase getBrawlShop(); -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/Fountain.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/Fountain.java deleted file mode 100644 index 90673463c..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/Fountain.java +++ /dev/null @@ -1,258 +0,0 @@ -package mineplex.core.brawl.fountain; - -import mineplex.core.account.CoreClientManager; -import mineplex.core.brawl.fountain.gui.FountainShop; -import mineplex.core.common.SortedSchematicLoader; -import mineplex.core.common.block.schematic.UtilSchematic; -import mineplex.core.common.util.C; -import mineplex.core.common.util.Callback; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilText; -import mineplex.core.donation.DonationManager; -import mineplex.core.hologram.Hologram; -import mineplex.core.hologram.HologramManager; -import mineplex.core.stats.StatsManager; -import mineplex.serverdata.Region; -import mineplex.serverdata.redis.counter.GoalCounter; -import mineplex.serverdata.redis.counter.GoalCounterListener; -import mineplex.serverdata.servers.ConnectionData; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.TimeZone; - -/** - * Represents a fountain that players can add gems to, with a reward for reaching specific goals - * @author Shaun Bennett - */ -public class Fountain implements GoalCounterListener -{ - // Manager Injections - private final HologramManager _hologramManager; - private final StatsManager _statsManager; - - private boolean _brawlActive; - private final String _name; - private final String _dataKey; - private final Location _location; - private final Hologram _hologram; - private final GoalCounter _counter; -// private final BlockProgressBar _blockProgressBar; - private final SortedSchematicLoader _schematicLoader; - - private final FountainShop _shop; - - public Fountain(ConnectionData writeConnection, ConnectionData readConnection, Region region, Location location, Location pasteLocation, String name, String dataKey, long goal, FountainManager fountainManager, - CoreClientManager clientManager, DonationManager donationManager, HologramManager hologramManager, - StatsManager statsManager) - { - _hologramManager = hologramManager; - _statsManager = statsManager; - - _name = name; - _dataKey = dataKey; - _location = location; - _hologram = new Hologram(hologramManager, new Location(location.getWorld(), -23, 75, 3), name).start(); - _counter = new GoalCounter(writeConnection, readConnection, region, dataKey, goal); - _counter.addListener(this); - _brawlActive = false; -// _blockProgressBar = new BlockProgressBar(_lavaLocation.getBlock(), Material.LAVA, BlockFace.UP); - _schematicLoader = new SortedSchematicLoader<>(pasteLocation); - loadSchematics(); - - _shop = new FountainShop(this, fountainManager, clientManager, donationManager); - - updateVisuals(); - } - - private void loadSchematics() - { - try - { - _schematicLoader.addSchematic(0.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain0.schematic"))); - _schematicLoader.addSchematic(0.2, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain20.schematic"))); - _schematicLoader.addSchematic(0.4, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain40.schematic"))); - _schematicLoader.addSchematic(0.6, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain60.schematic"))); - _schematicLoader.addSchematic(0.8, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain80.schematic"))); - _schematicLoader.addSchematic(1.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain100.schematic"))); - _schematicLoader.addSchematic(2.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain200.schematic"))); - _schematicLoader.addSchematic(3.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain300.schematic"))); - } - catch (IOException e) - { - System.err.println("Failed to load Gem Fountain Schematics"); - e.printStackTrace(); - } - } - - protected void updateVisuals() - { - double fillPercent = getFillPercent(); - - if (isBrawlActive()) - { - ArrayList text = new ArrayList<>(); - if (fillPercent >= 1) - { - text.add(C.cRed + C.Bold + "Weekend Brawl is Active!"); - if (fillPercent >= 2) - { - text.add("Bonus Reward Unlocked:"); - if (fillPercent >= 3) - { - text.add(C.cGreen + "3X Experience in Brawl"); - } - else - { - text.add(C.cGreen + "2X Experience in Brawl"); - } - } - text.add(" "); - text.add("Speak to the Fountain Keeper to Join!"); - } - else - { - text.add(C.cRed + "Brawl goal was not met"); - text.add("Come back next week"); - } - - _hologram.setText(text.toArray(new String[text.size()])); - //_schematicLoader.update(fillPercent); - } - else - { - double flatPercent = fillPercent - (int) fillPercent; - - String fillColor; - String emptyColor; - String goalMessage; - - if (fillPercent < 1) - { - fillColor = C.cGreen; - emptyColor = C.cRed; - goalMessage = "100% to Unlock Weekend Brawl"; - } else if (fillPercent < 2) - { - fillColor = C.cYellow; - emptyColor = C.cGreen; - goalMessage = "200% to Unlock 2x XP for Weekend Brawl"; - } else if (fillPercent < 3) - { - fillColor = C.cAqua; - emptyColor = C.cYellow; - goalMessage = "300% to Unlock 3x XP for Weekend Brawl"; - } else - { - fillColor = C.cAqua; - emptyColor = C.cYellow; - goalMessage = "All Rewards Unlocked!"; - flatPercent = 1; - } - - int intPercent = (int) (fillPercent * 100); - String progressBar = UtilText.getProgress(null, flatPercent, null, false, 30, emptyColor, fillColor); - _hologram.setText(_name + C.Reset + " " + intPercent + "%", goalMessage, progressBar); - _schematicLoader.update(fillPercent); - } - } - - public void increment(Player player, long amount, Callback callback) - { - _statsManager.incrementStat(player, getStatName(), amount); - _statsManager.runAsync(() -> { - long count = _counter.addAndGet(amount); - _statsManager.runSync(() -> { - updateVisuals(); - if (callback != null) callback.run(count); - }); - }); - } - - public long getAmountAdded(Player player) - { - return _statsManager.Get(player).getStat(getStatName()); - } - - private final String getStatName() - { - return "Global.Fountain." + getDataKey(); - } - - public String getName() - { - return _name; - } - - public String getDataKey() - { - return _dataKey; - } - - public void openShop(Player player) - { - _shop.attemptShopOpen(player); - } - - public double getFillPercent() - { - return Math.min(3, _counter.getFillPercent()); - } - - public long getCount() - { - return _counter.getCount(); - } - - public void reset() - { - _counter.reset(); - updateVisuals(); - } - - @Override - public void onMilestone(GoalCounter counter, int milestone) - { - switch (milestone) - { - case 1: - Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 100%! Brawl Game unlocked this week")); - break; - case 2: - Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 200%! 2x XP enabled for Brawl!")); - break; - case 3: - Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 300%! 3x XP enabled for Brawl!")); - break; - } - } - - public void updateBrawlActive() - { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("PST")); - int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); - if (dayOfWeek == Calendar.FRIDAY || dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) - { - _brawlActive = true; - } - else - { - _brawlActive = false; - } - } - - public void updateCounter() - { - _counter.updateCount(); - } - - public boolean isBrawlActive() - { - return _brawlActive; - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/FountainManager.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/FountainManager.java deleted file mode 100644 index e7c009f3f..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/FountainManager.java +++ /dev/null @@ -1,123 +0,0 @@ -package mineplex.core.brawl.fountain; - -import mineplex.core.MiniPlugin; -import mineplex.core.account.CoreClientManager; -import mineplex.core.brawl.fountain.command.FountainCommand; -import mineplex.core.common.util.C; -import mineplex.core.donation.DonationManager; -import mineplex.core.hologram.HologramManager; -import mineplex.core.locations.LocationConstants; -import mineplex.core.stats.StatsManager; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; -import mineplex.serverdata.Region; -import mineplex.serverdata.servers.ConnectionData; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.plugin.java.JavaPlugin; - -/** - * @author Shaun Bennett - */ -public class FountainManager extends MiniPlugin -{ - private HologramManager _hologramManager; - private StatsManager _statsManager; - private DonationManager _donationManager; - // used so we can inject the brawl shop (only on hub) into fountain code - private BrawlShopProvider _brawlShopProvider; - - private Fountain _gemFountain; - - public FountainManager(JavaPlugin plugin, CoreClientManager clientManager, DonationManager donationManager, HologramManager hologramManager, StatsManager statsManager, BrawlShopProvider shopProvider) - { - super("Counter", plugin); - - _hologramManager = hologramManager; - _statsManager = statsManager; - _donationManager = donationManager; - _brawlShopProvider = shopProvider; - - World world = Bukkit.getWorlds().get(0);//-43.5, 66, -38.5 - - int goal = 35000000;//!new File("eu.dat").exists() ? 200000000 : 20000000; - _gemFountain = new Fountain(new ConnectionData("10.3.203.80", 6379, ConnectionData.ConnectionType.MASTER, "USRedis"), - new ConnectionData("10.3.203.80", 6377, ConnectionData.ConnectionType.SLAVE, "USRedis"), Region.ALL, - LocationConstants.FOUNTAIN_LOCATION, LocationConstants.FOUNTAIN_SCHEMATIC, - C.cGreen + "Gem Fountain", "GemFountain_01", goal, this, clientManager, donationManager, _hologramManager, _statsManager); - } - - @Override - public void addCommands() - { - addCommand(new FountainCommand(this)); - } - - @EventHandler - public void updateFountainCount(UpdateEvent event) - { - if (event.getType() != UpdateType.SEC) - return; - - _gemFountain.updateBrawlActive(); - _gemFountain.updateVisuals(); - } - - @EventHandler - public void updateCounter(UpdateEvent event) - { - if (event.getType() != UpdateType.SEC_05) - return; - - runAsync(_gemFountain::updateCounter); - } - - @EventHandler - public void onInteractAtEntity(PlayerInteractAtEntityEvent event) - { - Entity entity = event.getRightClicked(); - if (entity.getCustomName() != null && entity.isCustomNameVisible()) - { - if (entity.getCustomName().contains("Weekend Brawl") && getBrawlShopProvider() != null) - { - getBrawlShopProvider().getBrawlShop().attemptShopOpen(event.getPlayer()); - } - } - } - - @EventHandler - public void onDamage(EntityDamageByEntityEvent event) - { - if (!(event.getDamager() instanceof Player)) - return; - - Entity entity = event.getEntity(); - if (entity.getCustomName() != null && entity.isCustomNameVisible()) - { - if (entity.getCustomName().contains("Weekend Brawl") && getBrawlShopProvider() != null) - { - getBrawlShopProvider().getBrawlShop().attemptShopOpen(((Player) event.getDamager())); - } - } - } - - public Fountain getGemFountain() - { - return _gemFountain; - } - - public DonationManager getDonationManager() - { - return _donationManager; - } - - public BrawlShopProvider getBrawlShopProvider() - { - return _brawlShopProvider; - } -} \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/GemFountainSalesPackage.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/GemFountainSalesPackage.java deleted file mode 100644 index d0ba3e882..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/GemFountainSalesPackage.java +++ /dev/null @@ -1,20 +0,0 @@ -package mineplex.core.brawl.fountain; - -import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.shop.item.SalesPackageBase; -import org.bukkit.Material; - -/** - * @author Shaun Bennett - */ -public class GemFountainSalesPackage extends SalesPackageBase -{ - public GemFountainSalesPackage(int gems) - { - super("Add " + gems + " Gems", Material.EMERALD, (byte) 0, new String[] {}, gems, 1); - - CurrencyCostMap.put(GlobalCurrency.GEM, gems); - KnownPackage = false; - OneTimePurchaseOnly = false; - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/AddCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/AddCommand.java deleted file mode 100644 index bebc34341..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/AddCommand.java +++ /dev/null @@ -1,69 +0,0 @@ -package mineplex.core.brawl.fountain.command; - -import java.util.function.Consumer; - -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.command.CommandBase; -import mineplex.core.common.Rank; -import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.common.util.Callback; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.server.util.TransactionResponse; - -import org.bukkit.entity.Player; - -/** - * Command to add gems to the fountain - * - * @author Shaun Bennett - */ -public class AddCommand extends CommandBase -{ - public AddCommand(FountainManager plugin) - { - super(plugin, Rank.DEVELOPER, "add"); - } - - @Override - public void Execute(Player caller, String[] args) - { - if (args == null || args.length != 1) - { - help(caller); - return; - } - - try - { - int amount = Integer.parseInt(args[0]); - - Plugin.getDonationManager().purchaseUnknownSalesPackage(caller, "GemFountain.Add", GlobalCurrency.GEM, amount, false, - result -> - { - if (result == TransactionResponse.Success) - { - Plugin.getGemFountain().increment(caller, amount, null); - UtilPlayer.message(caller, F.main("Fountain", "Added " + F.elem(amount) + " to the fountain!")); - } - else if (result == TransactionResponse.InsufficientFunds) - { - UtilPlayer.message(caller, F.main("Fountain", "You do not have enough gems!")); - } - else - { - UtilPlayer.message(caller, F.main("Fountain", "There was an error processing your request!")); - } - }); - } - catch (NumberFormatException ex) - { - help(caller); - } - } - - private void help(Player player) - { - UtilPlayer.message(player, F.help("/fountain add", "", Rank.DEVELOPER)); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/FountainCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/FountainCommand.java deleted file mode 100644 index 555ad39d2..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/FountainCommand.java +++ /dev/null @@ -1,27 +0,0 @@ -package mineplex.core.brawl.fountain.command; - -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.command.MultiCommandBase; -import mineplex.core.common.Rank; -import org.bukkit.entity.Player; - -/** - * @author Shaun Bennett - */ -public class FountainCommand extends MultiCommandBase -{ - public FountainCommand(FountainManager plugin) - { - super(plugin, Rank.DEVELOPER, "fountain"); - - AddCommand(new AddCommand(plugin)); - AddCommand(new GuiCommand(plugin)); - AddCommand(new ResetCommand(plugin)); - } - - @Override - protected void Help(Player caller, String[] args) - { - - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/GuiCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/GuiCommand.java deleted file mode 100644 index 2a6b1d667..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/GuiCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package mineplex.core.brawl.fountain.command; - -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.command.CommandBase; -import mineplex.core.common.Rank; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilPlayer; -import org.bukkit.entity.Player; - -/** - * Command to open the fountain gui without speaking to the fountain keeper - * @author Shaun Bennett - */ -public class GuiCommand extends CommandBase -{ - public GuiCommand(FountainManager plugin) - { - super(plugin, Rank.DEVELOPER, "gui"); - } - - @Override - public void Execute(Player caller, String[] args) - { - Plugin.getGemFountain().openShop(caller); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/ResetCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/ResetCommand.java deleted file mode 100644 index 4589eb2a4..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/command/ResetCommand.java +++ /dev/null @@ -1,26 +0,0 @@ -package mineplex.core.brawl.fountain.command; - -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.command.CommandBase; -import mineplex.core.common.Rank; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilPlayer; -import org.bukkit.entity.Player; - -/** - * Command to reset the fountain - * @author Shaun Bennett - */ -public class ResetCommand extends CommandBase -{ - public ResetCommand(FountainManager plugin) - { - super(plugin, Rank.DEVELOPER, "reset"); - } - - @Override - public void Execute(Player caller, String[] args) - { - Plugin.getGemFountain().reset(); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainPage.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainPage.java deleted file mode 100644 index dc3fb9c64..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainPage.java +++ /dev/null @@ -1,92 +0,0 @@ -package mineplex.core.brawl.fountain.gui; - -import mineplex.core.account.CoreClientManager; -import mineplex.core.brawl.fountain.Fountain; -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.brawl.fountain.gui.button.FountainAddButton; -import mineplex.core.common.MaterialData; -import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.common.util.C; -import mineplex.core.donation.DonationManager; -import mineplex.core.shop.item.ShopItem; -import mineplex.core.shop.page.ShopPageBase; -import org.bukkit.Material; -import org.bukkit.entity.Player; - -/** - * @author Shaun Bennett - */ -public class FountainPage extends ShopPageBase -{ - private final MaterialData EMPTY_XP = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 7); - private final MaterialData XP = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 5); - private final MaterialData EMPTY_XP100 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 5); - private final MaterialData XP100 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 4); - private final MaterialData EMPTY_XP200 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 4); - private final MaterialData XP200 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 3); - private final int[] XP_SLOTS = { 2, 3, 4, 5, 6 }; - - private Fountain _fountain; - - public FountainPage(FountainManager plugin, FountainShop shop, CoreClientManager clientManager, DonationManager donationManager, Fountain fountain, Player player) - { - super(plugin, shop, clientManager, donationManager, "Fountain Keeper", player, 27); - - _fountain = fountain; - - buildPage(); - } - - @Override - protected void buildPage() - { - // Experience Bar - long added = _fountain.getAmountAdded(getPlayer()); - final double fillPercent = _fountain.getFillPercent(); - String title = ((int)(fillPercent * 100)) + "% Complete"; - boolean canAdd = fillPercent < 3; - - String unlockMessage; - if (fillPercent < 1) unlockMessage = "Reach 100% to unlock Weekend Brawl Game"; - else if (fillPercent < 2) unlockMessage = "Reach 200% to unlock 2x XP in Brawl"; - else if (fillPercent < 3) unlockMessage = "Reach 300% to unlock 3x XP in Brawl"; - else unlockMessage = "All rewards unlocked!"; - - String[] lore = new String[] { - " ", - C.cWhite + unlockMessage, - " ", - C.cWhite + "You have added " + C.cGreen + added + " Gems"}; - - final double percentForEach = 1D / XP_SLOTS.length; - double check = percentForEach; - - double flatPercent = fillPercent == 3 ? 1 : fillPercent - ((int) fillPercent); - for (int i = 0; i < XP_SLOTS.length; i++) - { - MaterialData data; - if (fillPercent < 1) data = flatPercent >= check ? XP : EMPTY_XP; - else if (fillPercent < 2) data = flatPercent >= check ? XP100 : EMPTY_XP100; - else data = flatPercent >= check ? XP200 : EMPTY_XP200; - ShopItem shopItem = new ShopItem(data.getMaterial(), data.getData(), title, - lore, 1, false, false); - - setItem(XP_SLOTS[i], shopItem); - check += percentForEach; - } - - if (canAdd) - { - int playerGems = getDonationManager().Get(getPlayer()).getBalance(GlobalCurrency.GEM); - ShopItem add1 = new ShopItem(Material.EMERALD, "Add 100 Gems", new String[]{}, 1, playerGems < 100, false); - ShopItem add2 = new ShopItem(Material.EMERALD, "Add 1,000 Gems", new String[]{}, 64, playerGems < 1000, false); - ShopItem add3 = new ShopItem(Material.EMERALD_BLOCK, "Add 10,000 Gems", new String[]{}, 1, playerGems < 10000, false); - ShopItem add4 = new ShopItem(Material.EMERALD_BLOCK, "Add 100,000 Gems", new String[]{}, 64, playerGems < 100000, false); - // Buttons - addButton(19, add1, new FountainAddButton(this, 100)); - addButton(21, add2, new FountainAddButton(this, 1000)); - addButton(23, add3, new FountainAddButton(this, 10000)); - addButton(25, add4, new FountainAddButton(this, 100000)); - } - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainShop.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainShop.java deleted file mode 100644 index a8cade6e4..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/FountainShop.java +++ /dev/null @@ -1,48 +0,0 @@ -package mineplex.core.brawl.fountain.gui; - -import mineplex.core.account.CoreClientManager; -import mineplex.core.brawl.fountain.Fountain; -import mineplex.core.brawl.fountain.FountainManager; -import mineplex.core.donation.DonationManager; -import mineplex.core.shop.ShopBase; -import mineplex.core.shop.page.ShopPageBase; -import org.bukkit.entity.Player; - -/** - * @author Shaun Bennett - */ -public class FountainShop extends ShopBase -{ - private final Fountain _fountain; - - public FountainShop(Fountain fountain, FountainManager plugin, CoreClientManager clientManager, DonationManager donationManager) - { - super(plugin, clientManager, donationManager, "Fountain Keeper"); - - _fountain = fountain; - } - - @Override - protected ShopPageBase> buildPagesFor(Player player) - { - return new FountainPage(getPlugin(), this, getClientManager(), getDonationManager(), _fountain, player); - } - - public Fountain getFountain() - { - return _fountain; - } - - @Override - public boolean attemptShopOpen(Player player) - { - if (_fountain.isBrawlActive() && getPlugin().getBrawlShopProvider() != null) - { - return getPlugin().getBrawlShopProvider().getBrawlShop().attemptShopOpen(player); - } - else - { - return super.attemptShopOpen(player); - } - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/button/FountainAddButton.java b/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/button/FountainAddButton.java deleted file mode 100644 index 3dcc6ebd7..000000000 --- a/Plugins/Mineplex.Core/src/mineplex/core/brawl/fountain/gui/button/FountainAddButton.java +++ /dev/null @@ -1,38 +0,0 @@ -package mineplex.core.brawl.fountain.gui.button; - -import mineplex.core.brawl.fountain.GemFountainSalesPackage; -import mineplex.core.brawl.fountain.gui.FountainPage; -import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.shop.confirmation.ConfirmationPage; -import mineplex.core.shop.item.IButton; -import mineplex.core.shop.item.SalesPackageBase; -import mineplex.core.shop.item.SalesPackageProcessor; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; - -/** - * @author Shaun Bennett - */ -public class FountainAddButton implements IButton -{ - private final FountainPage _page; - private final int _gems; - private final SalesPackageBase _salesPackage; - - public FountainAddButton(FountainPage page, int gems) - { - _page = page; - _gems = gems; - _salesPackage = new GemFountainSalesPackage(gems); - } - - @Override - public void onClick(Player player, ClickType clickType) - { - _page.getShop().openPageForPlayer(player, new ConfirmationPage<>(player, _page, new SalesPackageProcessor(player, GlobalCurrency.GEM, _salesPackage, _page.getDonationManager(), () -> - { - _page.getPlugin().getGemFountain().increment(player, _gems, null); - _page.refresh(); - }), _salesPackage.buildIcon())); - } -} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/fallingblock/FallingBlocks.java b/Plugins/Mineplex.Core/src/mineplex/core/fallingblock/FallingBlocks.java index 46b462c17..b7655b19f 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/fallingblock/FallingBlocks.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/fallingblock/FallingBlocks.java @@ -33,7 +33,7 @@ public class FallingBlocks extends MiniPlugin if (vec.getY() < 0) { - vec.setY(vec.getY() * -1); + vec.setY(-vec.getY()); } Spawn(location, type, data, vec); @@ -46,7 +46,6 @@ public class FallingBlocks extends MiniPlugin UtilAction.velocity(fall, velocity, 0.5 + 0.25 * Math.random(), false, 0, 0.4 + 0.20 * Math.random(), 10, false); - fall.setMetadata(METADATA, new FixedMetadataValue(_plugin, "x")); UtilEnt.SetMetadata(fall, METADATA, "x"); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphBobRoss.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphBobRoss.java index 7217d82c6..5b1984ba5 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphBobRoss.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/morph/MorphBobRoss.java @@ -5,11 +5,9 @@ import java.time.YearMonth; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; import mineplex.core.common.util.C; import mineplex.core.common.util.LineFormat; @@ -21,12 +19,16 @@ import mineplex.core.hologram.Hologram; import mineplex.core.hologram.HologramManager; import mineplex.core.itemstack.ItemStackFactory; import mineplex.core.recharge.Recharge; +import mineplex.core.treasure.event.TreasureFinishEvent; +import mineplex.core.treasure.event.TreasureStartEvent; import org.bukkit.Bukkit; +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.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -48,17 +50,14 @@ import mineplex.core.utils.UtilGameProfile; */ public class MorphBobRoss extends MorphGadget { + /** Radius within which painting is not allowed near treasure chests */ + private static final int TREASURE_RADIUS = 4; + /** The inventory slot in which the paint brush is placed */ private static final int PAINT_BRUSH_SLOT = 2; - /** Max # of blocks that can be destroyed every quarter second, per player */ - private static final int DESTROY_LIMIT = 4; - - /** The # of seconds for which paint blocks exist */ - private static final int PAINT_SECONDS = 30; - - /** The # of minutes after which the code will stop trying to remove paint */ - private static final int PAINT_EXPIRE = 10; + /** The # of milliseconds for which paint blocks exist */ + private static final long PAINT_MILLISECONDS = 30000; /** Height above a player's location at which quotes are to be displayed */ private static final double QUOTE_HEIGHT = 2.25; @@ -196,10 +195,11 @@ public class MorphBobRoss extends MorphGadget /** Map of items in players' inventories */ private final Map _inventoryItems = new HashMap<>(); - private final Map _paintColors = new HashMap<>(); + /** Colors that are being used by painting players */ + private final Map _paintColors = new HashMap<>(); - /** Blocks that have been painted */ - private final List _paintBlocks = new ArrayList<>(); + /** Locations at which treasure is currently being opened */ + private final Map _openingTreasure = new HashMap<>(); private final HologramManager _holograms; @@ -277,6 +277,7 @@ public class MorphBobRoss extends MorphGadget { if (Recharge.Instance.use(event.getPlayer(), COLOR_KEY, COLOR_COOLDOWN, false, false)) { + changePaintColor(event.getPlayer(), true); } } @@ -284,6 +285,7 @@ public class MorphBobRoss extends MorphGadget { if (Recharge.Instance.use(event.getPlayer(), COLOR_KEY, COLOR_COOLDOWN, false, false)) { + changePaintColor(event.getPlayer(), false); } } @@ -296,40 +298,7 @@ public class MorphBobRoss extends MorphGadget @EventHandler public void updateEvent(UpdateEvent event) { - if (event.getType() == UpdateType.FASTER) // do paint removal - { - int limit = 0; - int offset = 0; - - // destroy paint blocks that are too old - while (!_paintBlocks.isEmpty() - && offset < _paintBlocks.size() - && _paintBlocks.get(offset).time < System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(PAINT_SECONDS) - && limit < DESTROY_LIMIT * getActive().size()) - { - Block block = _paintBlocks.get(offset).block; - - if (block.getType() == Material.CARPET) - { - _paintBlocks.remove(offset); - block.setType(Material.AIR); - limit++; - } - else - { - // stop trying to remove paint after a certain amount of time - if (_paintBlocks.get(offset).time > System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(PAINT_EXPIRE)) - { - _paintBlocks.remove(offset); - } - else - { - offset++; - } - } - } - } - else if (event.getType() == UpdateType.TICK) // do quote displaying + if (event.getType() == UpdateType.TICK) // do quote displaying { for (Player player : getActive()) { @@ -377,10 +346,12 @@ public class MorphBobRoss extends MorphGadget if (item.getType() == Material.STICK && player.getItemInHand().equals(item)) { + togglePainting(player); } else if (!player.getItemInHand().equals(item) && item.getType() != Material.STICK) { + togglePainting(player); } } @@ -401,6 +372,14 @@ public class MorphBobRoss extends MorphGadget return; } + for (Location location : _openingTreasure.values()) + { + if (location.toVector().isInSphere(event.getPlayer().getLocation().toVector(), TREASURE_RADIUS)) + { + return; + } + } + // check if the player has been issued a paintbrush if (_inventoryItems.containsKey(player.getUniqueId())) { @@ -419,28 +398,15 @@ public class MorphBobRoss extends MorphGadget // check that there is room to paint and that the block below is solid and not more paint. if ((block.isEmpty() || carpet) && UtilBlock.fullSolid(down) && !UtilBlock.bottomSlab(down)) { - int index; - PaintedBlock blk = new PaintedBlock(block); - - if (carpet) // if block is a carpet + // if the block is a non-paint carpet + if (carpet && !Manager.getBlockRestore().contains(block)) { - // remove old paint if it was painted - if ((index = _paintBlocks.indexOf(blk)) != -1) - { - _paintBlocks.remove(index); - } - else // if it's non-paint carpet - { - return; // don't paint - } + return; // don't paint } // mark block as painted - _paintBlocks.add(blk); - - // actually paint block - block.setType(Material.CARPET); - block.setData((byte) (15 - item.getData().getData())); + Manager.getBlockRestore().add(block, Material.CARPET.getId(), (byte) (15 - item.getData().getData()), + block.getTypeId(), block.getData(), PAINT_MILLISECONDS); } } } @@ -456,6 +422,7 @@ public class MorphBobRoss extends MorphGadget UUID uuid = event.getPlayer().getUniqueId(); _inventoryItems.remove(uuid); _paintColors.remove(uuid); + } } @@ -466,6 +433,7 @@ public class MorphBobRoss extends MorphGadget */ private void changePaintColor(Player player, boolean reverse) { + ItemStack item = _inventoryItems.remove(player.getUniqueId()); byte data = selectPaintColor(player, reverse); @@ -483,22 +451,27 @@ public class MorphBobRoss extends MorphGadget */ private void togglePainting(Player player) { + ItemStack item = _inventoryItems.remove(player.getUniqueId()); ItemStack newItem; if (item.getType() == Material.STICK) { - byte data = selectPaintColor(player, false); + byte data; + if (!_paintColors.containsKey(player.getUniqueId())) + { + data = selectPaintColor(player, false); + } + else + { + data = COLOR_ORDER[_paintColors.get(player.getUniqueId())]; + } + newItem = ItemStackFactory.Instance.CreateStack(Material.INK_SACK, data, 1, PAINT_COLORS[data] + " " + PAINT_BRUSHES[ThreadLocalRandom.current().nextInt(0, PAINT_BRUSHES.length)]); } else { - if (_paintColors.containsKey(player.getUniqueId())) - { - _paintColors.remove(player.getUniqueId()); - } - newItem = ItemStackFactory.Instance.CreateStack(Material.STICK, (byte) 0, 1, BRUSH_NAME); } @@ -521,11 +494,11 @@ public class MorphBobRoss extends MorphGadget { UUID uuid = player.getUniqueId(); - int value; + byte value; if (!_paintColors.containsKey(uuid)) { - value = ThreadLocalRandom.current().nextInt(0, 16); + value = (byte) ThreadLocalRandom.current().nextInt(0, 16); _paintColors.put(uuid, value); } else @@ -588,43 +561,24 @@ public class MorphBobRoss extends MorphGadget } /** - * Data class holding information on blocks which have been painted + * Disable painting in the area around treasure being opened. */ - private class PaintedBlock + @EventHandler(priority = EventPriority.LOW) + public void disableOnTreasureStart(TreasureStartEvent event) { - /** The time at which the block was painted */ - long time; + _openingTreasure.put(event.getPlayer().getUniqueId(), event.getPlayer().getLocation()); + Manager.getBlockRestore().restoreBlockAround(Material.CARPET, event.getPlayer().getLocation(), TREASURE_RADIUS); + } - /** The block which was painted */ - Block block; - - /** - * Construct a PaintedBlock - * - * @param block The block which has been painted. - */ - public PaintedBlock(Block block) + /** + * Enable painting in the area around treasure no longer being opened. + */ + @EventHandler(priority = EventPriority.HIGH) + public void enableOnTreasureFinish(TreasureFinishEvent event) + { + if (_openingTreasure.containsKey(event.getPlayer().getUniqueId())) { - this.block = block; - this.time = System.currentTimeMillis(); - } - - /** - * Overrides default equals behavior to have comparisons between - * multiple {@link PaintedBlock} objects match comparisons between - * their contained {@link PaintedBlock#block} fields. - */ - @Override - public boolean equals(Object o) - { - if (o instanceof PaintedBlock) - { - return block.equals(((PaintedBlock) o).block); - } - else - { - return super.equals(o); - } + _openingTreasure.remove(event.getPlayer().getUniqueId()); } } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/particle/ParticleCoalFumes.java b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/particle/ParticleCoalFumes.java index 467db55d2..236bc1e8a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/particle/ParticleCoalFumes.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gadget/gadgets/particle/ParticleCoalFumes.java @@ -20,7 +20,7 @@ public class ParticleCoalFumes extends ParticleGadget public ParticleCoalFumes(GadgetManager manager) { super(manager, "Coal Fumes", - UtilText.splitLineToArray(C.cGray + "Being on the Naughty List does have some perks... if you love coal, that is...", LineFormat.LORE), + UtilText.splitLineToArray(C.cGray + "Being on the Naughty List does have some hattori... if you love coal, that is...", LineFormat.LORE), -1, Material.COAL, (byte) 0); } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java index 6f6f38241..8b7ec8606 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/game/GameDisplay.java @@ -104,6 +104,10 @@ public enum GameDisplay AlienInvasion("Alien Invasion", Material.ENDER_STONE, (byte) 0, GameCategory.EVENT, 69, false), + MOBA("Heroes of GWEN", Material.SKULL_ITEM, (byte)1, GameCategory.CLASSICS, 70, true), + + GemHunters("Gem Hunters", Material.EMERALD, (byte) 0, GameCategory.SURVIVAL, 71, false), + Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999, false), Brawl("Brawl", Material.DIAMOND, (byte) 0, GameCategory.EVENT, 998, false); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/gui/SimpleGui.java b/Plugins/Mineplex.Core/src/mineplex/core/gui/SimpleGui.java index 0029d1864..65e341389 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/gui/SimpleGui.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/gui/SimpleGui.java @@ -82,16 +82,23 @@ public class SimpleGui implements ItemRefresher, Listener { Validate.isTrue(i >= 0 && i < _size, "Tried to add a gui item outside of inventory range"); - GuiItem oldItem = getItem(i); - if (oldItem != null) oldItem.close(); - - if (item != null) + try { - _items[i] = item; - item.setup(); - } + GuiItem oldItem = getItem(i); + if (oldItem != null) oldItem.close(); - refreshItem(i); + if (item != null) + { + _items[i] = item; + item.setup(); + } + + refreshItem(i); + } catch (Exception ex) + { + System.err.println("Failed to add item " + item + " to GUI " + this + ": "); + ex.printStackTrace(); + } } public GuiItem getItem(int i) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java index 603f5e150..8a07b03fa 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemBuilder.java @@ -1,13 +1,7 @@ package mineplex.core.itemstack; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilInv; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Color; @@ -21,10 +15,18 @@ import org.bukkit.inventory.meta.BannerMeta; import org.bukkit.inventory.meta.FireworkEffectMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.potion.PotionEffect; -import mineplex.core.common.util.C; -import mineplex.core.common.util.UtilInv; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; public class ItemBuilder { @@ -53,14 +55,15 @@ public class ItemBuilder private Color _color; private short _data; private short _durability; - private final HashMap _enchants = new HashMap(); - private final List _lore = new ArrayList(); + private final Map _enchants = new HashMap<>(); + private final List _lore = new ArrayList<>(); private Material _mat; private String _title = null; private boolean _unbreakable; private boolean _glow; private String _playerHeadName = null; - private HashSet _itemFlags = new HashSet(); + private Set _itemFlags = new HashSet<>(); + private List _potionEffects = new ArrayList<>(); public ItemBuilder(ItemStack item) { @@ -86,6 +89,13 @@ public class ItemBuilder { setColor(((LeatherArmorMeta) meta).getColor()); } + else if (meta instanceof PotionMeta) + { + for (PotionEffect effect : ((PotionMeta) meta).getCustomEffects()) + { + addPotionEffect(effect); + } + } _itemFlags.addAll(meta.getItemFlags()); @@ -124,7 +134,7 @@ public class ItemBuilder return this; } - public HashSet getItemFlags() + public Set getItemFlags() { return _itemFlags; } @@ -279,6 +289,22 @@ public class ItemBuilder { ((BannerMeta) meta).setBaseColor(DyeColor.getByColor(_color)); } + else if (meta instanceof PotionMeta) + { + PotionMeta potionMeta = (PotionMeta) meta; + + for (PotionEffect effect : _potionEffects) + { + potionMeta.addCustomEffect(effect, true); + } + + if (!_potionEffects.isEmpty()) + { + potionMeta.setMainEffect(_potionEffects.get(0).getType()); + } + + meta = potionMeta; + } meta.addItemFlags(getItemFlags().toArray(new ItemFlag[0])); meta.spigot().setUnbreakable(isUnbreakable()); @@ -307,7 +333,7 @@ public class ItemBuilder } newBuilder.setColor(_color); - // newBuilder.potion = potion; + newBuilder.setDurability(_durability); newBuilder.setData(_data); @@ -321,11 +347,16 @@ public class ItemBuilder newBuilder.setItemFlags(_itemFlags); newBuilder.setPlayerHead(_playerHeadName); + + for (PotionEffect potionEffect : _potionEffects) + { + newBuilder.addPotionEffect(potionEffect); + } return newBuilder; } - public HashMap getAllEnchantments() + public Map getAllEnchantments() { return _enchants; } @@ -452,4 +483,9 @@ public class ItemBuilder return this; } + public ItemBuilder addPotionEffect(PotionEffect effect) + { + _potionEffects.add(effect); + return this; + } } \ No newline at end of file diff --git a/Plugins/Mineplex.Core/src/mineplex/core/npc/Npc.java b/Plugins/Mineplex.Core/src/mineplex/core/npc/Npc.java index ff1d19ffa..59abe10de 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/npc/Npc.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/npc/Npc.java @@ -188,4 +188,10 @@ public class Npc { _location = location; } + + @Override + public String toString() + { + return "NPC[entity=" + _entity + "]"; + } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRepository.java index 0e007abdb..ee0e0201a 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRepository.java @@ -104,8 +104,6 @@ public class PowerPlayClubRepository implements Listener { PowerPlayData cached = getCachedData(player); - List list = PowerPlayClubRewards.rewardsForMonths(cached.getUsableCosmeticMonths()); - PowerPlayClubRewards.rewardsForMonths(cached.getUsableCosmeticMonths()).forEach(item -> item.reward(player)); // Gives Metal Man for anyone subscribed diff --git a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java index 02388b67c..83fc019ad 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayClubRewards.java @@ -49,6 +49,15 @@ public class PowerPlayClubRewards void reward(Player player); } + private static final PowerPlayClubItem MISSING = new PowerPlayClubItem() + { + @Override + public String getPrizeName() { return "Coming soon!"; } + + @Override + public void reward(Player player) { } + }; + private static class UnknownSalesPackageItem implements PowerPlayClubItem { private static final DonationManager _donationManager = Managers.require(DonationManager.class); @@ -104,7 +113,7 @@ public class PowerPlayClubRewards public static List rewardsForMonths(Set months) { - return months.stream().sorted().map(rewards::get).collect(Collectors.toList()); + return months.stream().sorted().map(PowerPlayClubRewards::getReward).collect(Collectors.toList()); } public static Map rewards() @@ -112,6 +121,10 @@ public class PowerPlayClubRewards return rewards; } + public static PowerPlayClubItem getReward(YearMonth month) + { + return rewards.getOrDefault(month, MISSING); + } public static void giveAllItems(Player player, InventoryManager inventoryManager, PowerPlayClubRepository repo) { diff --git a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayData.java b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayData.java index f478de57c..3d2524ff7 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayData.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/powerplayclub/PowerPlayData.java @@ -1,12 +1,18 @@ package mineplex.core.powerplayclub; -import com.google.common.base.Objects; - import java.time.LocalDate; import java.time.YearMonth; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; +import com.google.common.base.MoreObjects; + public class PowerPlayData { /* If this is set, the player's subscription is planned to recur. @@ -19,6 +25,9 @@ public class PowerPlayData */ private final Optional _nextClaimDate; + // The source set of subscriptions from which this was built + private final List _subscriptions; + // The months where the player hasn't claimed chests/amplifiers private final Set _unclaimedMonths; @@ -29,11 +38,11 @@ public class PowerPlayData */ private final Set _cosmeticMonths; - static PowerPlayData fromSubsAndClaims(List subscriptions, List claimedMonths) + public static PowerPlayData fromSubsAndClaims(List subscriptions, List claimedMonths) { if (subscriptions.isEmpty()) { - return new PowerPlayData(Optional.empty(), new HashSet<>(), new HashSet<>()); + return new PowerPlayData(subscriptions, Optional.empty(), new HashSet<>(), new HashSet<>()); } final LocalDate today = LocalDate.now(); @@ -96,7 +105,7 @@ public class PowerPlayData .map(YearMonth::from) .collect(Collectors.toSet()); - return new PowerPlayData(nextClaimDate, unclaimedMonths, cosmeticMonths); + return new PowerPlayData(subscriptions, nextClaimDate, unclaimedMonths, cosmeticMonths); } private static List buildMonths(Subscription subscription) @@ -126,10 +135,10 @@ public class PowerPlayData } } - static class Subscription + public static class Subscription { - private final LocalDate _startDate; - private final SubscriptionDuration _duration; + public final LocalDate _startDate; + public final SubscriptionDuration _duration; Subscription(LocalDate startDate, SubscriptionDuration duration) { @@ -143,13 +152,19 @@ public class PowerPlayData MONTH, YEAR } - private PowerPlayData(Optional nextClaimDate, Set unclaimedMonths, Set cosmeticMonths) + private PowerPlayData(List subscriptions, Optional nextClaimDate, Set unclaimedMonths, Set cosmeticMonths) { + _subscriptions = subscriptions; _nextClaimDate = nextClaimDate; _unclaimedMonths = unclaimedMonths; _cosmeticMonths = cosmeticMonths; } + public List getSubscriptions() + { + return _subscriptions; + } + public Optional getNextClaimDate() { return _nextClaimDate; @@ -173,7 +188,7 @@ public class PowerPlayData @Override public String toString() { - return Objects.toStringHelper(this) + return MoreObjects.toStringHelper(this) .add("_nextClaimDate", _nextClaimDate) .add("_unclaimedMonths", _unclaimedMonths) .add("_cosmeticMonths", _cosmeticMonths) diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/Quest.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/Quest.java new file mode 100644 index 000000000..d5a24a69e --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/Quest.java @@ -0,0 +1,240 @@ +package mineplex.core.quests; + +import org.bukkit.ChatColor; + +import mineplex.core.game.GameCategory; +import mineplex.core.game.GameDisplay; + +/** + * Quest + * + * @author xXVevzZXx + */ +public class Quest +{ + private static final Object _progressLock = new Object(); + + private int _questID; + + private String _questName; + private String _questTask; + + private int _questCost; + private String _questReward; + + private QuestRarity _rarity; + + private String _type; + + private GameDisplay _game; + private GameCategory _gameCategory; + private boolean _generalGame; + private boolean _overworld; + + private TriggerType _trigger; + private String[] _item; + private int _statToComplete; + + private long _lastCompleted; + + private int _current; + + private int _timesCompleted; + + public Quest(int questID, String name, String task, int cost, String reward, QuestRarity rarity, String type, TriggerType trigger, String[] item, int statToComplete) + { + _questID = questID; + _questName = name; + _questTask = task; + _questCost = cost; + _questReward = reward; + _rarity = rarity; + _trigger = trigger; + _item = item; + _statToComplete = statToComplete; + _type = type; + + if (GameDisplay.matchName(type) != null) + _game = GameDisplay.matchName(type); + + try + { + _gameCategory = GameCategory.valueOf(type); + } + catch (IllegalArgumentException e) {} + + _generalGame = _type.equalsIgnoreCase("General"); + + if (!_generalGame) + _overworld = (_game == null && _gameCategory == null); + } + + public int getID() + { + return _questID; + } + + public String getName() + { + return _questName; + } + + public String getTask() + { + return _questTask; + } + + public int getCost() + { + return _questCost; + } + + public String getReward() + { + return _questReward; + } + + public QuestRarity getRarity() + { + return _rarity; + } + + public GameDisplay getGame() + { + return _game; + } + + public GameCategory getGameCategory() + { + return _gameCategory; + } + + public boolean isInOverworld() + { + return _overworld; + } + + public TriggerType getTrigger() + { + return _trigger; + } + + public String[] getItem() + { + return _item; + } + + public int getStatToComplete() + { + return _statToComplete; + } + + public int getProgress() + { + return _current; + } + + public void setProgress(int progress) + { + _current = progress; + } + + public void increment(int value) + { + synchronized (_progressLock) + { + _current += value; + } + } + + public void increment() + { + synchronized (_progressLock) + { + _current++; + } + } + + public void decrement(int value) + { + synchronized (_progressLock) + { + _current -= value; + } + } + + public void decrement() + { + synchronized (_progressLock) + { + _current--; + } + } + + public boolean isCompleted() + { + return _current >= _statToComplete; + } + + public void setLastCompleted(long time) + { + _lastCompleted = time; + } + + public long getLastCompleted() + { + return _lastCompleted; + } + + public String getRewardName() + { + return _questReward.split(":")[0]; + } + + public int getRewardAmount() + { + return Integer.parseInt(_questReward.split(":")[1]); + } + + public void setTimesCompleted(int amount) + { + _timesCompleted = amount; + } + + public int getTimesCompleted() + { + return _timesCompleted; + } + + public boolean isActive() + { + return _current != -1; + } + + public String[] getQuestInfo() + { + String[] info = new String[]{ + ChatColor.LIGHT_PURPLE + getTask(), "", ChatColor.GRAY + "Reward: " + ChatColor.AQUA + getRewardAmount() + " " + getRewardName(), + "", + ChatColor.GRAY + "Progress: " + + (_current == -1 ? ChatColor.RED + "Not in your " + QuestManager.QUEST_NAME + " Inventory" : + (isCompleted() ? ChatColor.GREEN + "Completed!" : + ChatColor.YELLOW + "" + getProgress() + ChatColor.GRAY + "/" + ChatColor.YELLOW + getStatToComplete())), + "", + getRarity().getColor() + "" + ChatColor.BOLD + getRarity().toString(), + }; + return info; + } + + public boolean isGeneral() + { + return _generalGame; + } + + @Override + public Quest clone() + { + return new Quest(_questID, _questName, _questTask, _questCost, _questReward, _rarity, _type, _trigger, _item, _statToComplete); + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestClientData.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestClientData.java new file mode 100644 index 000000000..74adc76e2 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestClientData.java @@ -0,0 +1,94 @@ +package mineplex.core.quests; + +import java.util.ArrayList; + +import mineplex.core.hologram.Hologram; + +/** + * QuestClientData + * + * @author xXVevzZXx + */ +public class QuestClientData +{ + private ArrayList _quests = new ArrayList<>(); + + private Hologram _hologram; + + public void addQuest(Quest quest) + { + _quests.add(quest); + } + + public ArrayList getQuests() + { + ArrayList quests = new ArrayList<>(); + for (Quest quest : _quests) + { + if (quest.getProgress() != -1) + quests.add(quest); + } + return quests; + } + + public boolean hasQuest(Quest quest) + { + for (Quest other : getQuests()) + { + if (other.getID() == quest.getID()) + return true; + } + return false; + } + + public Quest getQuest(int id) + { + for (Quest quest : getQuests()) + { + if (quest.getID() == id) + return quest; + } + return null; + } + + public Quest getQuestFromAll(int id) + { + for (Quest quest : _quests) + { + if (quest.getID() == id) + return quest; + } + return null; + } + + public boolean hasQuestFromAll(Quest quest) + { + for (Quest other : _quests) + { + if (other.getID() == quest.getID()) + return true; + } + return false; + } + + public void removeQuest(int id) + { + Quest toRemove = getQuest(id); + toRemove.setProgress(-1); + } + + public ArrayList getAllQuests() + { + return _quests; + } + + public Hologram getHologram() + { + return _hologram; + } + + public void setHologram(Hologram hologram) + { + _hologram = hologram; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestManager.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestManager.java new file mode 100644 index 000000000..26741b195 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestManager.java @@ -0,0 +1,416 @@ +package mineplex.core.quests; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; + +import net.md_5.bungee.api.ChatColor; + +import org.apache.commons.lang3.tuple.Triple; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Slime; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerJoinEvent; + +import mineplex.core.MiniClientPlugin; +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.Pair; +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.C; +import mineplex.core.common.util.Callback; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.donation.DonationManager; +import mineplex.core.google.GoogleSheetsManager; +import mineplex.core.hologram.Hologram; +import mineplex.core.hologram.HologramManager; +import mineplex.core.inventory.InventoryManager; +import mineplex.core.npc.Npc; +import mineplex.core.npc.NpcManager; +import mineplex.core.quests.command.GetQuestCommand; +import mineplex.core.quests.command.IncrementQuestCommand; +import mineplex.core.quests.command.OpenGuiCommand; +import mineplex.core.quests.repository.QuestRepository; +import mineplex.core.quests.shop.QuestShop; +import mineplex.core.stats.StatsManager; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.quest.client.RedisQuestSupplier; +import mineplex.quest.common.QuestSupplier; +import mineplex.serverdata.redis.messaging.PubSubJedisClient; +import mineplex.serverdata.redis.messaging.PubSubRouter; +import mineplex.serverdata.servers.ServerManager; + +/** + * QuestManager + * + * @author xXVevzZXx + */ +public class QuestManager extends MiniClientPlugin +{ + public static final String QUEST_NAME = "Mineplex Mission"; + + private static final String GOOGLE_SHEET = "QUESTS_SHEET"; + private static final String GOOGLE_TABLE = "Quests"; + + private QuestRepository _repository; + private GoogleSheetsManager _sheetsManager; + private CoreClientManager _clients; + private DonationManager _donationManager; + private InventoryManager _inventoryManager; + + public ArrayList _availableQuests; + + private QuestSupplier _questSupplier = new RedisQuestSupplier(getPlugin(), new PubSubRouter(new PubSubJedisClient(ServerManager.getMasterConnection(), ServerManager.getSlaveConnection()))); + + private Npc _questNPC; + private boolean _enableNPC; + private HologramManager _hologramManager; + private boolean _visualTick; + + public QuestManager(HologramManager hologramManager, Location npc, InventoryManager inventoryManager, DonationManager donationManager) + { + super("Quest Manager"); + + _repository = new QuestRepository(); + _sheetsManager = require(GoogleSheetsManager.class); + _clients = require(CoreClientManager.class); + _availableQuests = new ArrayList<>(); + _donationManager = donationManager; + _inventoryManager = inventoryManager; + _hologramManager = hologramManager; + + setupQuests(); + + _questNPC = require(NpcManager.class).getNpcByName("Mineplex Missions"); + if (_questNPC == null) + { + _enableNPC = false; + } + else + { + Slime slime = (Slime) _questNPC.getEntity(); + slime.setSize(3); + if (npc != null) + { + _questNPC.setLocation(npc); + } + _enableNPC = true; + } + } + + @EventHandler + public void updateCreeper(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER || !_enableNPC) + return; + + Slime slime = (Slime)_questNPC.getEntity(); + slime.setSize(3); + + for (Player player : UtilServer.getPlayers()) + { + String prefix = _visualTick ? C.cAqua : C.cDAqua; + updateSlimeVisual(player, prefix); + } + + _visualTick = !_visualTick; + } + + + + public void updateSlimeVisual(Player player , String rewardPrefix) + { + if (!_enableNPC) + return; + + int availableQuests = 5; + + for (int questid : getCurrentQuests()) + { + if (Get(player).getQuestFromAll(questid) == null) + continue; + + Quest quest = Get(player).getQuestFromAll(questid); + + if (quest.isActive()) + availableQuests--; + + if (!UtilTime.elapsed(quest.getLastCompleted(), 1000*60*60*24)) + availableQuests--; + } + + Hologram hologram; + + QuestClientData client = Get(player); + + if (client.getHologram() == null) + { + double yAdd = 2.3; + if(!UtilPlayer.is1_9(player)) + { + yAdd = 2.45; + } + hologram = new Hologram(_hologramManager, _questNPC.getLocation().clone().add(0, yAdd, 0), ""); + hologram.setHologramTarget(Hologram.HologramTarget.WHITELIST); + hologram.addPlayer(player); + client.setHologram(hologram); + hologram.start(); + } + else + { + hologram = client.getHologram(); + } + + if (availableQuests > 0) + { + // Hologram + String text = rewardPrefix + availableQuests + " Mission" + (availableQuests > 1 ? "s" : "") + " Available"; + hologram.setText(text); + } + else + { + String text = C.cGray + "No Missions Available"; + hologram.setText(text); + } + } + + @Override + public void addCommands() + { + addCommand(new OpenGuiCommand(this)); + addCommand(new GetQuestCommand(this)); + addCommand(new IncrementQuestCommand(this)); + } + + public void setupQuests() + { + _availableQuests.clear(); + Map>> sheet = _sheetsManager.getSheetData(GOOGLE_SHEET); + List> table = new ArrayList<>(); + for (String key : sheet.keySet()) + { + if (key.equalsIgnoreCase(GOOGLE_TABLE)) + table = sheet.get(key); + } + + int size = table.size(); + + for (int i = 1; i < size; i++) + { + String id = table.get(i).get(0); + String name = table.get(i).get(1); + String task = table.get(i).get(2); + String type = table.get(i).get(3); + String cost = table.get(i).get(4); + String reward = table.get(i).get(5); + String trigger = table.get(i).get(6); + String statcompletion = table.get(i).get(7); + String item = table.get(i).get(8); + String rarity = table.get(i).get(9); + + _availableQuests.add(new Quest(Integer.parseInt(id), name, task, + Integer.parseInt(cost), + reward, + QuestRarity.getByName(rarity), + type, + TriggerType.getByName(trigger), + item.split(","), + Integer.parseInt(statcompletion))); + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void openGui(PlayerInteractAtEntityEvent event) + { + if (!_enableNPC) + return; + + Entity entity = event.getRightClicked(); + if (entity.equals(_questNPC.getEntity())) + { + new QuestShop(this, _clients, _donationManager).attemptShopOpen(event.getPlayer()); + } + } + + @EventHandler + public void openGui(EntityDamageByEntityEvent event) + { + if (!_enableNPC) + return; + + if (event.getDamager() instanceof Player) + { + Player player = (Player) event.getDamager(); + if (event.getEntity().equals(_questNPC.getEntity())) + { + new QuestShop(this, _clients, _donationManager).attemptShopOpen(player); + } + } + } + + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + QuestClientData questData = Get(event.getPlayer()); + _repository.getQuests(_clients.Get(event.getPlayer()), new Callback>>>() + { + @Override + public void run(ArrayList>> data) + { + for (Pair> pair : data) + { + int id = pair.getLeft(); + int value = pair.getRight().getLeft(); + long time = pair.getRight().getMiddle(); + int timesCompleted = pair.getRight().getRight(); + + for (Quest quest : _availableQuests) + { + if (quest.getID() == id) + { + Quest clone = quest.clone(); + clone.setProgress(value); + clone.setLastCompleted(time); + clone.setTimesCompleted(timesCompleted); + questData.addQuest(clone); + } + } + } + } + }); + } + + public Quest getQuestByID(int id) + { + for (Quest quest : _availableQuests) + { + if (quest.getID() == id) + return quest; + } + return null; + } + + public void addNewQuest(Player player, Quest quest) + { + QuestClientData data = Get(player); + for (Quest other : data.getAllQuests()) + { + if (other.getID() == quest.getID()) + { + other.setProgress(0); + _repository.addQuest(_clients.Get(player), other); + return; + } + } + + Quest clone = quest.clone(); + clone.setProgress(0); + Get(player).addQuest(clone); + _repository.addNew(_clients.Get(player), quest); + } + + public void resetQuest(Player player, Quest quest, boolean completed) + { + if (completed) + { + quest.setTimesCompleted(quest.getTimesCompleted() + 1); + quest.setLastCompleted(System.currentTimeMillis()); + } + + Get(player).removeQuest(quest.getID()); + _repository.resetQuest(_clients.Get(player), quest, completed); + } + + public void incrementQuest(Player player, Quest quest, int value) + { + quest.increment(value); + if (quest.isCompleted()) + { + UtilPlayer.message(player, F.main(QUEST_NAME, "You have completed the " + QUEST_NAME + ": " + ChatColor.YELLOW + quest.getName())); + } + _repository.incrementQuest(_clients.Get(player), quest, value); + } + + public Set getCurrentQuests() + { + Set set = new HashSet<>(); + for (mineplex.quest.common.Quest quest : _questSupplier.get()) + { + set.add(quest.getUniqueId()); + } + return set; + } + + public void rewardQuest(Player player, Quest quest, Consumer callback) + { + if (quest.getReward().contains(":")) + { + ChatColor color = ChatColor.YELLOW; + if (quest.getRewardName().equalsIgnoreCase("Shards")) + { + _donationManager.rewardCurrency(GlobalCurrency.TREASURE_SHARD, player, "Completing " + QUEST_NAME + ": " + quest.getID(), Integer.parseInt(quest.getReward().split(":")[1]), callback); + color = ChatColor.AQUA; + } + else if (quest.getRewardName().equalsIgnoreCase("Gems")) + { + _donationManager.rewardCurrency(GlobalCurrency.TREASURE_SHARD, player, "Completing " + QUEST_NAME + ": " + quest.getID(), Integer.parseInt(quest.getReward().split(":")[1]), callback); + color = ChatColor.GREEN; + } + else if (quest.getRewardName().equalsIgnoreCase("XP")) + { + require(StatsManager.class).incrementStat(player, "Global.ExpEarned", quest.getRewardAmount()); + callback.accept(true); + } + else + { + _inventoryManager.addItemToInventory(player, quest.getRewardName(), quest.getRewardAmount()); + callback.accept(true); + } + UtilPlayer.message(player, F.main(QUEST_NAME, "You have recieved " + color + quest.getRewardAmount() + " " + quest.getRewardName() + " " + ChatColor.GRAY + "for completing: " + ChatColor.YELLOW + quest.getName())); + } + } + + public CoreClientManager getClients() + { + return _clients; + } + + public DonationManager getDonations() + { + return _donationManager; + } + + public InventoryManager getInventoryManager() + { + return _inventoryManager; + } + + @Override + protected QuestClientData addPlayer(UUID uuid) + { + return new QuestClientData(); + } + + @Override + public void saveData(String name, int accountId) + { + Get(name).getHologram().stop(); + } + + public ArrayList getAvailableQuests() + { + return _availableQuests; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestRarity.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestRarity.java new file mode 100644 index 000000000..860fa52c8 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/QuestRarity.java @@ -0,0 +1,44 @@ +package mineplex.core.quests; + +import org.bukkit.ChatColor; + +/** + * QuestRarity + * + * @author xXVevzZXx + */ +public enum QuestRarity +{ + COMMON("Common", ChatColor.YELLOW), RARE("Rare", ChatColor.LIGHT_PURPLE), LEGENDARY("Legendary", ChatColor.GREEN); + + private String _name; + private ChatColor _color; + + private QuestRarity(String name, ChatColor color) + { + _name = name; + _color = color; + } + + @Override + public String toString() + { + return _name; + } + + public ChatColor getColor() + { + return _color; + } + + public static QuestRarity getByName(String name) + { + for (QuestRarity rarity : values()) + { + if (rarity.toString().equalsIgnoreCase(name)) + return rarity; + } + return null; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/TriggerType.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/TriggerType.java new file mode 100644 index 000000000..861999fae --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/TriggerType.java @@ -0,0 +1,36 @@ +package mineplex.core.quests; + +/** + * TriggerType + * + * @author xXVevzZXx + */ +public enum TriggerType +{ + + KILL("Kill"), DIE("Die"), WIN("Win"), LOSE("Lose"), COLLECT("Collect"), PLAY("Play"), COMPLETE("Complete"); + + private String _name; + + private TriggerType(String name) + { + _name = name; + } + + @Override + public String toString() + { + return _name; + } + + public static TriggerType getByName(String name) + { + for (TriggerType type : values()) + { + if (type.toString().equalsIgnoreCase(name)) + return type; + } + return null; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/command/GetQuestCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/GetQuestCommand.java new file mode 100644 index 000000000..1b7fe9cc8 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/GetQuestCommand.java @@ -0,0 +1,55 @@ +package mineplex.core.quests.command; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestManager; + +/** + * GetQuestCommand + * + * @author xXVevzZXx + */ +public class GetQuestCommand extends CommandBase +{ + public GetQuestCommand(QuestManager plugin) + { + super(plugin, Rank.ADMIN, "GetMineplexMission"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, "You have to submit valid arguments")); + return; + } + + if (Plugin.getQuestByID(Integer.parseInt(args[0])) == null) + { + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, QuestManager.QUEST_NAME + " not found")); + return; + } + + Player player = caller; + if (args.length == 2) + { + if (UtilPlayer.searchExact(args[1]) != null) + player = UtilPlayer.searchExact(args[1]); + } + + Quest quest = Plugin.getQuestByID(Integer.parseInt(args[0])); + + Plugin.addNewQuest(player, quest); + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "Added " + QuestManager.QUEST_NAME + ": " + ChatColor.YELLOW + quest.getName())); + + if (caller != player) + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, "You gave the " + QuestManager.QUEST_NAME + ": " + ChatColor.YELLOW + quest.getName() + ChatColor.GRAY + " to " + ChatColor.YELLOW + player.getName())); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/command/IncrementQuestCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/IncrementQuestCommand.java new file mode 100644 index 000000000..0ebb57fb3 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/IncrementQuestCommand.java @@ -0,0 +1,67 @@ +package mineplex.core.quests.command; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestManager; + +/** + * CompleteQuestCommand + * + * @author xXVevzZXx + */ +public class IncrementQuestCommand extends CommandBase +{ + public IncrementQuestCommand(QuestManager plugin) + { + super(plugin, Rank.ADMIN, "IncrementMineplexMission"); + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 2) + { + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, "You have to submit valid arguments")); + return; + } + + Player player = caller; + if (args.length == 3) + { + if (UtilPlayer.searchExact(args[2]) != null) + player = UtilPlayer.searchExact(args[2]); + } + + if (Plugin.Get(player).getQuest(Integer.parseInt(args[0])) == null) + { + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, QuestManager.QUEST_NAME + " not found")); + return; + } + + int increment = 0; + try + { + increment = Integer.parseInt(args[1]); + } + catch (NumberFormatException e) + { + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, "You have to submit a valid number")); + return; + } + + Quest quest = Plugin.Get(player).getQuest(Integer.parseInt(args[0])); + + Plugin.incrementQuest(player, quest, increment); + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "Incremented " + QuestManager.QUEST_NAME + ": " + ChatColor.YELLOW + quest.getName() + ChatColor.GRAY + " by " + increment)); + + if (caller != player) + UtilPlayer.message(caller, F.main(QuestManager.QUEST_NAME, "You incremented the " + QuestManager.QUEST_NAME + ": " + ChatColor.YELLOW + quest.getName() + ChatColor.GRAY + " for " + ChatColor.YELLOW + player.getName() + ChatColor.GRAY + " by " + increment)); + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/command/OpenGuiCommand.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/OpenGuiCommand.java new file mode 100644 index 000000000..df0f68f2c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/command/OpenGuiCommand.java @@ -0,0 +1,27 @@ +package mineplex.core.quests.command; + +import org.bukkit.entity.Player; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.quests.QuestManager; +import mineplex.core.quests.shop.QuestShop; + +/** + * OpenGuiCommand + * + * @author xXVevzZXx + */ +public class OpenGuiCommand extends CommandBase +{ + public OpenGuiCommand(QuestManager plugin) + { + super(plugin, Rank.ALL, "Missions"); + } + + @Override + public void Execute(Player caller, String[] args) + { + new QuestShop(Plugin, Plugin.getClients(), Plugin.getDonations()).attemptShopOpen(caller); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/event/QuestInteractEvent.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/event/QuestInteractEvent.java new file mode 100644 index 000000000..2ebc13f8d --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/event/QuestInteractEvent.java @@ -0,0 +1,60 @@ +package mineplex.core.quests.event; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import mineplex.core.quests.Quest; + +/** + * QuestBuyEvent + * + * @author xXVevzZXx + */ +public class QuestInteractEvent extends Event +{ + private static final HandlerList handlers = new HandlerList(); + + private boolean _cancelled = false; + + private Quest _quest; + + private String _cancelReason; + + public QuestInteractEvent(Quest quest) + { + _quest = quest; + } + + public Quest getQuest() + { + return _quest; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + public boolean isCancelled() + { + return _cancelled; + } + + public void setCancelled(String reason) + { + _cancelled = true; + _cancelReason = reason; + } + + public String getCancelMessage() + { + return _cancelReason; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/repository/QuestRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/repository/QuestRepository.java new file mode 100644 index 000000000..4592781c1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/repository/QuestRepository.java @@ -0,0 +1,140 @@ +package mineplex.core.quests.repository; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +import org.apache.commons.lang3.tuple.Triple; + +import mineplex.core.account.CoreClient; +import mineplex.core.common.Pair; +import mineplex.core.common.util.Callback; +import mineplex.core.common.util.UtilServer; +import mineplex.core.quests.Quest; +import mineplex.serverdata.database.DBPool; +import mineplex.serverdata.database.RepositoryBase; +import mineplex.serverdata.database.ResultSetCallable; +import mineplex.serverdata.database.column.ColumnInt; +import mineplex.serverdata.database.column.ColumnLong; + +/** + * QuestRepository + * + * @author xXVevzZXx + */ +public class QuestRepository extends RepositoryBase +{ + private static final String INSTERT_NEW_QUEST = "INSERT INTO accountQuest (accountId, questId, progress, questCompletion, lastCompleted) VALUES (?, ?, ?, ?, ?);"; + private static final String INCREMENT_QUEST = "UPDATE accountQuest SET progress=progress+? WHERE accountId=? AND questId=?;"; + private static final String RESET_QUEST = "UPDATE accountQuest SET progress=-1 WHERE accountId=? AND questId=?;"; + private static final String START_QUEST = "UPDATE accountQuest SET progress=0 WHERE accountId=? AND questId=?;"; + private static final String COMPLETE_QUEST = "UPDATE accountQuest SET progress=-1, questCompletion=questCompletion+1, lastCompleted=? WHERE accountId=? AND questId=?;"; + + private static final String FETCH_QUESTS = "SELECT questId, progress, questCompletion, lastCompleted FROM accountQuest WHERE accountId=?"; + + public String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS accountQuest (id INT NOT NULL AUTO_INCREMENT, accountId INT NOT NULL, questId INT NOT NULL, progress INT, questCompletion INT, lastCompleted BIGINT NOT NULL, PRIMARY KEY (id), FOREIGN KEY (accountId) REFERENCES accounts (id), UNIQUE INDEX questIndex (accountId, questId), INDEX progressIndex (progress), INDEX completionIndex (questCompletion));"; + + public QuestRepository() + { + super(DBPool.getAccount()); + + createTable(); + } + + public void createTable() + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + executeUpdate(CREATE_TABLE); + } + }); + } + + public void getQuests(CoreClient client, Callback>>> callback) + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + executeQuery(FETCH_QUESTS, new ResultSetCallable() + { + @Override + public void processResultSet(ResultSet resultSet) throws SQLException + { + ArrayList>> list = new ArrayList<>(); + while (resultSet.next()) + { + list.add(Pair.create(resultSet.getInt(1), Triple.of(resultSet.getInt(2), resultSet.getLong(4), resultSet.getInt(3)))); + } + callback.run(list); + } + } ,new ColumnInt("accountId", client.getAccountId())); + } + }); + } + + public void resetQuest(CoreClient client, Quest quest, boolean completed) + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + if (completed) + { + executeUpdate(COMPLETE_QUEST, new ColumnLong("lastCompleted", System.currentTimeMillis()), new ColumnInt("accountId", client.getAccountId()), new ColumnInt("questId", quest.getID())); + } + else + { + executeUpdate(RESET_QUEST, new ColumnInt("accountId", client.getAccountId()), new ColumnInt("questId", quest.getID())); + } + } + }); + } + + public void addQuest(CoreClient client, Quest quest) + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + executeUpdate(START_QUEST, new ColumnInt("accountId", client.getAccountId()), new ColumnInt("questId", quest.getID())); + } + }); + } + + public void addNew(CoreClient client, Quest quest) + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + executeInsert(INSTERT_NEW_QUEST, null, + new ColumnInt("accountId", client.getAccountId()), + new ColumnInt("questId", quest.getID()), + new ColumnInt("progress", 0), + new ColumnInt("questCompletion", 0), + new ColumnLong("lastCompleted", (long) 0)); + } + }); + } + + public void incrementQuest(CoreClient client, Quest quest, int value) + { + UtilServer.runAsync(new Runnable() + { + @Override + public void run() + { + executeUpdate(INCREMENT_QUEST, new ColumnInt("progress", value), new ColumnInt("accountId", client.getAccountId()), new ColumnInt("questId", quest.getID())); + } + }); + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/BuyQuestButton.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/BuyQuestButton.java new file mode 100644 index 000000000..b1f70eea1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/BuyQuestButton.java @@ -0,0 +1,93 @@ +package mineplex.core.quests.shop; + +import net.md_5.bungee.api.ChatColor; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestManager; +import mineplex.core.quests.event.QuestInteractEvent; +import mineplex.core.recharge.Recharge; +import mineplex.core.shop.confirmation.ConfirmationPage; +import mineplex.core.shop.item.IButton; +import mineplex.core.shop.item.SalesPackageBase; +import mineplex.core.shop.item.SalesPackageProcessor; + +/** + * BuyQuestButton + * + * @author xXVevzZXx + */ +public class BuyQuestButton implements IButton +{ + private final static int MAX_QUESTS = 5; + + private QuestManager _questManager; + + private QuestPage _page; + + private Quest _quest; + + public BuyQuestButton(QuestManager questManager, QuestPage page, Quest quest) + { + _questManager = questManager; + _quest = quest; + _page = page; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + if (!Recharge.Instance.use(player, "Buy Mineplex Mission", 1000, false, false)) + { + return; + } + + if (_questManager.Get(player).hasQuest(_quest)) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You already own that " + QuestManager.QUEST_NAME + "!")); + return; + } + + if (_questManager.Get(player).getQuests().size() >= MAX_QUESTS) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You can't own more than " + MAX_QUESTS + " active " + QuestManager.QUEST_NAME + " at once!")); + return; + } + + if (_questManager.Get(player).hasQuestFromAll(_quest)) + { + if (!UtilTime.elapsed(_questManager.Get(player).getQuestFromAll(_quest.getID()).getLastCompleted(), 1000*60*60*24)) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You already completed that " + QuestManager.QUEST_NAME + " today!")); + return; + } + } + + QuestInteractEvent event = UtilServer.CallEvent(new QuestInteractEvent(_quest)); + if (event.isCancelled()) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, event.getCancelMessage())); + return; + } + + SalesPackageBase salesPackage = new QuestSale(ChatColor.YELLOW + "" + ChatColor.BOLD + _quest.getName(), Material.PAPER, _quest.getCost()); + _page.getShop().openPageForPlayer(player, new ConfirmationPage<>(player, _page, new SalesPackageProcessor(player, GlobalCurrency.GEM, salesPackage, _page.getDonationManager(), () -> + { + _questManager.addNewQuest(player, _quest); + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You have bought: " + ChatColor.YELLOW + _quest.getName())); + player.closeInventory(); + new QuestShop(_questManager, _questManager.getClients(), _questManager.getDonations()).attemptShopOpen(player); + + }), salesPackage.buildIcon())); + + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestPage.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestPage.java new file mode 100644 index 000000000..8dd619e51 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestPage.java @@ -0,0 +1,156 @@ +package mineplex.core.quests.shop; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.apache.commons.lang3.ArrayUtils; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.common.util.UtilTime; +import mineplex.core.donation.DonationManager; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestManager; +import mineplex.core.shop.item.IButton; +import mineplex.core.shop.page.ShopPageBase; + +/** + * QuestPage + * + * @author xXVevzZXx + */ +public class QuestPage extends ShopPageBase +{ + private QuestShop _questShop; + private QuestManager _manager; + + public QuestPage(QuestManager plugin, QuestShop shop, CoreClientManager clientManager, DonationManager donationManager, Player player) + { + super(plugin, shop, clientManager, donationManager, QuestManager.QUEST_NAME + " Page", player, 27); + + _questShop = shop; + _manager = plugin; + + buildPage(); + } + + @Override + protected void buildPage() + { + int i = 0; + setItem(i, ItemStackFactory.Instance.CreateStack(Material.EMERALD, (byte) 0, 1, ChatColor.RESET + "" + ChatColor.BOLD + "Available " + QuestManager.QUEST_NAME + "s")); + { + int currentSlot = 4; + int diff = 0; + boolean forward = true; + for (int questID : getQuestShop().getQuestManager().getCurrentQuests()) + { + if (forward) + { + currentSlot += diff; + } + else + { + currentSlot -= diff; + } + diff++; + forward = !forward; + + Quest playerQuest = _shop.getQuestManager().Get(_player).getQuestFromAll(questID); + if (playerQuest != null) + { + if (!UtilTime.elapsed(playerQuest.getLastCompleted(), 1000*60*60*24)) + { + continue; + } + if (playerQuest.isActive()) + { + continue; + } + } + + Quest quest = _shop.getQuestManager().getQuestByID(questID); + + ItemStack item = new ItemStack(Material.PAPER); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(ChatColor.YELLOW + "" + ChatColor.BOLD + quest.getName()); + meta.setLore(Arrays.asList( + ChatColor.LIGHT_PURPLE + quest.getTask(), + "", + ChatColor.GRAY + "Cost: " + ChatColor.GREEN + quest.getCost() + " Gems", + ChatColor.GRAY + "Reward: " + ChatColor.AQUA + quest.getRewardAmount() + " " + quest.getRewardName(), + "", + quest.getRarity().getColor() + "" + ChatColor.BOLD + quest.getRarity().toString(), + "", + ChatColor.GREEN + "Click to buy " + QuestManager.QUEST_NAME + "!" + )); + item.setItemMeta(meta); + + addButton(i + currentSlot, item, new BuyQuestButton(_manager, this, quest)); + } + } + i = 9; + while (i < (9*2)) + { + setItem(i, ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.BLACK.getData())); + i++; + } + i = 9*2; + addButton(i, ItemStackFactory.Instance.CreateStack(Material.EMPTY_MAP, (byte) 0, 1, ChatColor.RESET + "" + ChatColor.BOLD + QuestManager.QUEST_NAME + " Stats"), new IButton() + { + @Override + public void onClick(Player player, ClickType clickType) + { + player.closeInventory(); + new QuestStatShop(_manager, _manager.getClients(), _manager.getDonations()).attemptShopOpen(player); + } + }); + + { + int currentSlot = 4; + int diff = 0; + boolean forward = true; + for (Quest quest : _shop.getQuestManager().Get(_player).getQuests()) + { + if (forward) + { + currentSlot += diff; + } + else + { + currentSlot -= diff; + } + diff++; + forward = !forward; + + ItemStack item = new ItemStack(Material.PAPER); + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(ChatColor.YELLOW + "" + ChatColor.BOLD + quest.getName()); + + meta.setLore(Arrays.asList(ArrayUtils.addAll(quest.getQuestInfo(), + "", + (quest.isCompleted() ? ChatColor.GREEN + "Left Click to Complete" : ChatColor.RED + "Shift Right-Click to cancel") + ))); + + item.setItemMeta(meta); + item.addUnsafeEnchantment(Enchantment.DURABILITY, 1); + + addButton(i + currentSlot, item, new RedeemDeclineQuestButton(_donationManager, _manager, quest)); + } + } + } + + public QuestShop getQuestShop() + { + return _questShop; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestSale.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestSale.java new file mode 100644 index 000000000..9ded66346 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestSale.java @@ -0,0 +1,25 @@ +package mineplex.core.quests.shop; + +import org.bukkit.Material; + +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.shop.item.SalesPackageBase; + +/** + * QuestSale + * + * @author xXVevzZXx + */ +public class QuestSale extends SalesPackageBase +{ + + public QuestSale(String name, Material mat, int cost) + { + super(name, mat, (byte) 0, new String[] {}, cost); + + KnownPackage = false; + OneTimePurchaseOnly = false; +// CurrencyCostMap.clear(); + CurrencyCostMap.put(GlobalCurrency.GEM, cost); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestShop.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestShop.java new file mode 100644 index 000000000..13d6e6a43 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestShop.java @@ -0,0 +1,34 @@ +package mineplex.core.quests.shop; + +import org.bukkit.entity.Player; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.quests.QuestManager; +import mineplex.core.shop.ShopBase; +import mineplex.core.shop.page.ShopPageBase; + +/** + * QuestShop + * + * @author xXVevzZXx + */ +public class QuestShop extends ShopBase +{ + public QuestShop(QuestManager plugin, CoreClientManager clientManager, DonationManager donationManager) + { + super(plugin, clientManager, donationManager, QuestManager.QUEST_NAME + " Shop"); + } + + @Override + protected ShopPageBase> buildPagesFor(Player player) + { + return new QuestPage(getPlugin(), this, getClientManager(), getDonationManager(), player); + } + + public QuestManager getQuestManager() + { + return getPlugin(); + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatShop.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatShop.java new file mode 100644 index 000000000..2c805b10c --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatShop.java @@ -0,0 +1,35 @@ +package mineplex.core.quests.shop; + +import org.bukkit.entity.Player; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.quests.QuestManager; +import mineplex.core.shop.ShopBase; +import mineplex.core.shop.page.ShopPageBase; + +/** + * QuestStatShop + * + * @author xXVevzZXx + */ +public class QuestStatShop extends ShopBase +{ + + public QuestStatShop(QuestManager plugin, CoreClientManager clientManager, DonationManager donationManager) + { + super(plugin, clientManager, donationManager, QuestManager.QUEST_NAME + " Stats"); + } + + @Override + protected ShopPageBase> buildPagesFor(Player player) + { + return new QuestStatsPage(getPlugin(), this, getClientManager(), getDonationManager(), player, 0); + } + + public QuestManager getQuestManager() + { + return getPlugin(); + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatsPage.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatsPage.java new file mode 100644 index 000000000..b2b2904a7 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/QuestStatsPage.java @@ -0,0 +1,128 @@ +package mineplex.core.quests.shop; + +import java.util.Arrays; + +import org.apache.commons.lang3.ArrayUtils; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import mineplex.core.account.CoreClientManager; +import mineplex.core.donation.DonationManager; +import mineplex.core.itemstack.ItemStackFactory; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestClientData; +import mineplex.core.quests.QuestManager; +import mineplex.core.shop.item.IButton; +import mineplex.core.shop.page.ShopPageBase; + +/** + * QuestStatsPage + * + * @author xXVevzZXx + */ +public class QuestStatsPage extends ShopPageBase +{ + private QuestStatShop _questShop; + private QuestManager _manager; + private int _siteIndex; + + public QuestStatsPage(QuestManager plugin, QuestStatShop shop, CoreClientManager clientManager, DonationManager donationManager, Player player, int site) + { + super(plugin, shop, clientManager, donationManager, QuestManager.QUEST_NAME + " Stats", player, 6*9); + + _siteIndex = site; + + _questShop = shop; + _manager = plugin; + + buildPage(); + } + + @Override + protected void buildPage() + { + removeButton(5*9); + removeButton((6*9) - 1); + + int questID = (_siteIndex * 5 * 9); + for (int i = 0; i < 9*5; i++) + { + Quest quest = _manager.getQuestByID(questID); + + if (quest == null) + { + setItem(i, null); + questID++; + continue; + } + + QuestClientData data = _manager.Get(getPlayer()); + ItemStack item = ItemStackFactory.Instance.CreateStack(Material.WOOL, DyeColor.GRAY.getWoolData(), 1, ChatColor.YELLOW + quest.getName()); + + if (data.hasQuestFromAll(quest)) + { + Quest used = data.getQuestFromAll(questID); + + item = ItemStackFactory.Instance.CreateStack(Material.PAPER, (byte) 0, 1, ChatColor.YELLOW + used.getName()); + ItemMeta meta = item.getItemMeta(); + meta.setLore(Arrays.asList(ArrayUtils.addAll(used.getQuestInfo(), + "", + ChatColor.GRAY + "Times Completed: " + ChatColor.YELLOW + used.getTimesCompleted() + ))); + item.setItemMeta(meta); + } + setItem(i, item); + + questID++; + } + + if (_siteIndex > 0) + { + addButton(5*9, ItemStackFactory.Instance.CreateStack(Material.SIGN, (byte) 0, 1, ChatColor.YELLOW + "Previous Page"), new IButton() + { + @Override + public void onClick(Player player, ClickType clickType) + { + _siteIndex--; + buildPage(); + } + }); + } + + if (((_siteIndex + 1) * 5 * 9) <= _manager.getAvailableQuests().size()) + { + addButton((6*9) - 1, ItemStackFactory.Instance.CreateStack(Material.SIGN, (byte) 0, 1, ChatColor.YELLOW + "Next Page"), new IButton() + { + @Override + public void onClick(Player player, ClickType clickType) + { + _siteIndex++; + buildPage(); + } + }); + } + + addButton(5*9 + 4, ItemStackFactory.Instance.CreateStack(Material.SIGN, (byte) 0, 1, ChatColor.YELLOW + "Back to " + QuestManager.QUEST_NAME + "s"), new IButton() + { + @Override + public void onClick(Player player, ClickType clickType) + { + player.closeInventory(); + new QuestShop(_manager, getClientManager(), getDonationManager()).attemptShopOpen(player); + } + }); + + } + + + public QuestStatShop getQuestStatsShop() + { + return _questShop; + } + +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/RedeemDeclineQuestButton.java b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/RedeemDeclineQuestButton.java new file mode 100644 index 000000000..19bbef7d9 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/quests/shop/RedeemDeclineQuestButton.java @@ -0,0 +1,101 @@ +package mineplex.core.quests.shop; + +import java.util.function.Consumer; + +import javax.jws.Oneway; + +import net.md_5.bungee.api.ChatColor; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; + +import mineplex.core.common.currency.GlobalCurrency; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.donation.DonationManager; +import mineplex.core.inventory.InventoryManager; +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestManager; +import mineplex.core.quests.event.QuestInteractEvent; +import mineplex.core.recharge.Recharge; +import mineplex.core.shop.item.IButton; + +/** + * RedeemDeclineQuest + * + * @author xXVevzZXx + */ +public class RedeemDeclineQuestButton implements IButton +{ + private QuestManager _questManager; + private DonationManager _donations; + + private Quest _quest; + + public RedeemDeclineQuestButton(DonationManager donations, QuestManager questManager, Quest quest) + { + _questManager = questManager; + _donations = donations; + _quest = quest; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + if (!Recharge.Instance.use(player, "Decline Mineplex Mission", 1000, false, false)) + { + return; + } + + if (!_questManager.Get(player).hasQuest(_quest)) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You don't own that " + QuestManager.QUEST_NAME + "!")); + return; + } + + QuestInteractEvent event = UtilServer.CallEvent(new QuestInteractEvent(_quest)); + if (event.isCancelled()) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, event.getCancelMessage())); + return; + } + + if (clickType == ClickType.SHIFT_RIGHT) + { + if (_quest.isCompleted()) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You can't cancel a completed " + QuestManager.QUEST_NAME + "!")); + return; + } + _questManager.resetQuest(player, _quest, false); + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You have cancelled that " + QuestManager.QUEST_NAME + "!")); + } + + if (clickType == ClickType.LEFT) + { + if (!_quest.isCompleted()) + { + UtilPlayer.message(player, F.main(QuestManager.QUEST_NAME, "You haven't completed that " + QuestManager.QUEST_NAME + " yet!")); + return; + } + + _questManager.rewardQuest(player, _quest, new Consumer() + { + @Override + public void accept(Boolean succes) + { + if (succes) + { + _questManager.resetQuest(player, _quest, true); + player.closeInventory(); + } + } + }); + } + + player.closeInventory(); + new QuestShop(_questManager, _questManager.getClients(), _donations).attemptShopOpen(player); + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/Track.java b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/Track.java index bb436bd21..d7db74382 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/Track.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/Track.java @@ -78,7 +78,7 @@ public class Track implements Listener return this._trackRequirements; } - public final String getStatName() + public String getStatName() { return "track." + _id; } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/TrackManager.java b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/TrackManager.java index eddb79bf6..05c6833d0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/TrackManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/TrackManager.java @@ -9,6 +9,7 @@ import java.util.function.Consumer; import mineplex.core.titles.tracks.award.AlienInvasionTrack; import mineplex.core.titles.tracks.award.AprilFools2017Track; +import mineplex.core.titles.tracks.standard.GemHuntersTrack; import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; @@ -79,6 +80,7 @@ public class TrackManager extends MiniPlugin // registerTrack(new SurvivorTrack()); registerTrack(new LevelerTrack()); registerTrack(new PerfectionistTrack()); + registerTrack(new GemHuntersTrack()); // Awarded tracks registerTrack(new Bridges2017Track()); diff --git a/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/standard/GemHuntersTrack.java b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/standard/GemHuntersTrack.java new file mode 100644 index 000000000..27d7bbcd1 --- /dev/null +++ b/Plugins/Mineplex.Core/src/mineplex/core/titles/tracks/standard/GemHuntersTrack.java @@ -0,0 +1,71 @@ +package mineplex.core.titles.tracks.standard; + +import mineplex.core.titles.tracks.Track; +import mineplex.core.titles.tracks.TrackFormat; +import mineplex.core.titles.tracks.TrackTier; +import net.md_5.bungee.api.ChatColor; + +public class GemHuntersTrack extends Track +{ + + public GemHuntersTrack() + { + super("gem-hunters-gems", "GH Millionaire", "This track is unlocked by earning gems in Gem Hunters"); + + getRequirements() + .addTier(new TrackTier( + "Beggar", + "Gain 1,000 Gems in Gem Hunters", + this::getStat, + 1000, + new TrackFormat(ChatColor.GRAY) + )) + .addTier(new TrackTier( + "Poor", + "Gain 5,000 Gems in Gem Hunters", + this::getStat, + 5000, + new TrackFormat(ChatColor.AQUA) + )) + .addTier(new TrackTier( + "Middle Class", + "Gain 7,500 Gems in Gem Hunters", + this::getStat, + 7500, + new TrackFormat(ChatColor.GREEN) + )) + .addTier(new TrackTier( + "Wealthy", + "Gain 10,000 Gems in Gem Hunters", + this::getStat, + 10000, + new TrackFormat(ChatColor.DARK_GREEN) + )) + .addTier(new TrackTier( + "Loaded", + "Gain 25,000 Gems in Gem Hunters", + this::getStat, + 25000, + new TrackFormat(ChatColor.GOLD) + )) + .addTier(new TrackTier( + "Millionaire", + "Gain 50,000 Gems in Gem Hunters", + this::getStat, + 50000, + new TrackFormat(ChatColor.GOLD, ChatColor.YELLOW) + )); + + getRequirements() + .withRequirement(1, "Gem Earned in Gem Hunters"); + } + + /** + * Overriding this means we can hit two birds with one stat. + */ + @Override + public String getStatName() + { + return "Gem Hunters.GemsEarned"; + } +} diff --git a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java index 264da1eae..33401bf40 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/treasure/TreasureLocation.java @@ -176,22 +176,21 @@ public class TreasureLocation implements Listener Treasure treasure = new Treasure(_treasureManager, player, rewards, treasureType.getRewardType(), _chestBlock, _chestSpawns, treasureType, _treasureManager.getBlockRestore(), _hologramManager, _statusManager); _currentTreasure = treasure; - TreasureStartEvent startEvent = new TreasureStartEvent(player, treasure, Arrays.asList(rewards)); - UtilServer.CallEvent(startEvent); - - UtilTextMiddle.display(treasureType.getName(), "Choose " + rewards.length + " " + UtilText.plural("Chest", rewards.length) + " To Open", 20, 180, 20, player); - UtilPlayer.message(player, F.main("Treasure", "Choose " + rewards.length + " " + UtilText.plural("Chest", rewards.length) + " To Open")); - - Location teleportLocation = treasure.getCenterBlock().getLocation().add(0.5, 0, 0.5); - teleportLocation.setPitch(player.getLocation().getPitch()); - teleportLocation.setYaw(player.getLocation().getYaw()); - for (Entity entity : player.getNearbyEntities(3, 3, 3)) { UtilAction.velocity(entity, UtilAlg.getTrajectory(entity.getLocation(), treasure.getCenterBlock().getLocation()).multiply(-1), 1.5, true, 0.8, 0, 1.0, true); } + Location teleportLocation = treasure.getCenterBlock().getLocation().add(0.5, 0, 0.5); + teleportLocation.setPitch(player.getLocation().getPitch()); + teleportLocation.setYaw(player.getLocation().getYaw()); + player.teleport(teleportLocation); + TreasureStartEvent startEvent = new TreasureStartEvent(player, treasure, Arrays.asList(rewards)); + UtilServer.CallEvent(startEvent); + + UtilTextMiddle.display(treasureType.getName(), "Choose " + rewards.length + " " + UtilText.plural("Chest", rewards.length) + " To Open", 20, 180, 20, player); + UtilPlayer.message(player, F.main("Treasure", "Choose " + rewards.length + " " + UtilText.plural("Chest", rewards.length) + " To Open")); _treasureManager.addOpenStat(player, treasureType); } @@ -363,6 +362,10 @@ public class TreasureLocation implements Listener { return; } + if (_currentTreasure.getCenterBlock().getWorld() != event.getTo().getWorld()) + { + return; + } double toDistanceFromCenter = _currentTreasure.getCenterBlock().getLocation().add(0.5, 1.5, 0.5).distanceSquared(event.getTo()); if (toDistanceFromCenter <= 16) { diff --git a/Plugins/Mineplex.Database/src/mineplex/database/tables/AccountQuest.java b/Plugins/Mineplex.Database/src/mineplex/database/tables/AccountQuest.java new file mode 100644 index 000000000..a5e501bd3 --- /dev/null +++ b/Plugins/Mineplex.Database/src/mineplex/database/tables/AccountQuest.java @@ -0,0 +1,114 @@ +package mineplex.database.tables; + +import org.jooq.impl.TableImpl; + +/** + * This class is generated by jOOQ. + */ +@javax.annotation.Generated( + value = { + "http://www.jooq.org", + "jOOQ version:3.5.2" + }, + comments = "This class is generated by jOOQ" +) +@java.lang.SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class AccountQuest //extends TableImpl implements java.io.Serializable, java.lang.Cloneable +{ + +// /** +// * +// */ +// private static final long serialVersionUID = -8158716179851336044L; +// +// /** +// * The reference instance of Account.accountStat +// */ +// public static final mineplex.database.tables.AccountStat accountStat = new mineplex.database.tables.AccountStat(); +// +// /** +// * The class holding records for this type +// */ +// @Override +// public java.lang.Class getRecordType() { +// return mineplex.database.tables.records.AccountQuestRecord.class; +// } +// +// /** +// * The column Account.accountStat.accountId. +// */ +// public final org.jooq.TableField accountId = createField("accountId", org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, ""); +// +// /** +// * The column Account.accountStat.statId. +// */ +// public final org.jooq.TableField statId = createField("statId", org.jooq.impl.SQLDataType.INTEGER.nullable(false), this, ""); +// +// /** +// * The column Account.accountStat.value. +// */ +// public final org.jooq.TableField value = createField("value", org.jooq.impl.SQLDataType.BIGINTUNSIGNED.defaulted(true), this, ""); +// +// /** +// * Create a Account.accountStat table reference +// */ +// public AccountQuest() +// { +// super("accountquest", null); +// } +// +// /** +// * Create an aliased Account.accountStat table reference +// */ +// public AccountQuest(java.lang.String alias) { +// this(alias, mineplex.database.tables.AccountQuest.accountStat); +// } +// +// private AccountQuest(java.lang.String alias, org.jooq.Table aliased) { +// this(alias, aliased, null); +// } +// +// private AccountQuest(java.lang.String alias, org.jooq.Table aliased, org.jooq.Field[] parameters) { +// super(alias, mineplex.database.Account.Account, aliased, parameters, ""); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.UniqueKey getPrimaryKey() { +// return mineplex.database.Keys.KEY_accountStat_PRIMARY; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public java.util.List> getKeys() { +// return java.util.Arrays.>asList(mineplex.database.Keys.KEY_accountStat_PRIMARY); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public java.util.List> getReferences() { +// return java.util.Arrays.>asList(mineplex.database.Keys.accountStat_account, mineplex.database.Keys.accountStat_stat); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public mineplex.database.tables.AccountStat as(java.lang.String alias) { +// return new mineplex.database.tables.AccountStat(alias, this); +// } +// +// /** +// * Rename this table +// */ +// public mineplex.database.tables.AccountStat rename(java.lang.String name) { +// return new mineplex.database.tables.AccountStat(name, null); +// } + +} diff --git a/Plugins/Mineplex.Database/src/mineplex/database/tables/records/AccountQuestRecord.java b/Plugins/Mineplex.Database/src/mineplex/database/tables/records/AccountQuestRecord.java new file mode 100644 index 000000000..8b1926b2e --- /dev/null +++ b/Plugins/Mineplex.Database/src/mineplex/database/tables/records/AccountQuestRecord.java @@ -0,0 +1,202 @@ +package mineplex.database.tables.records; + +import org.jooq.Table; + +/** + * AccountQuest + * + * @author xXVevzZXx + */ +public class AccountQuestRecord //extends org.jooq.impl.UpdatableRecordImpl implements java.io.Serializable, java.lang.Cloneable, org.jooq.Record3 +{ +// +// /** +// * +// */ +// private static final long serialVersionUID = 5171965369180094201L; +// +// public AccountQuestRecord(Table table) +// { +// super(table); +// } +// +// /** +// * Setter for Account.accountStat.accountId. +// */ +// public void setAccountId(java.lang.Integer value) { +// setValue(0, value); +// } +// +// /** +// * Getter for Account.accountStat.accountId. +// */ +// public java.lang.Integer getAccountId() { +// return (java.lang.Integer) getValue(0); +// } +// +// /** +// * Setter for Account.accountStat.statId. +// */ +// public void setStatId(java.lang.Integer value) { +// setValue(1, value); +// } +// +// /** +// * Getter for Account.accountStat.statId. +// */ +// public java.lang.Integer getStatId() { +// return (java.lang.Integer) getValue(1); +// } +// +// /** +// * Setter for Account.accountStat.value. +// */ +// public void setValue(org.jooq.types.ULong value) { +// setValue(2, value); +// } +// +// /** +// * Getter for Account.accountStat.value. +// */ +// public org.jooq.types.ULong getValue() { +// return (org.jooq.types.ULong) getValue(2); +// } +// +// // ------------------------------------------------------------------------- +// // Primary key information +// // ------------------------------------------------------------------------- +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Record2 key() { +// return (org.jooq.Record2) super.key(); +// } +// +// // ------------------------------------------------------------------------- +// // Record3 type implementation +// // ------------------------------------------------------------------------- +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Row3 fieldsRow() { +// return (org.jooq.Row3) super.fieldsRow(); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Row3 valuesRow() { +// return (org.jooq.Row3) super.valuesRow(); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Field field1() { +// return mineplex.database.tables.AccountStat.accountStat.accountId; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Field field2() { +// return mineplex.database.tables.AccountStat.accountStat.statId; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.Field field3() { +// return mineplex.database.tables.AccountStat.accountStat.value; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public java.lang.Integer value1() { +// return getAccountId(); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public java.lang.Integer value2() { +// return getStatId(); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public org.jooq.types.ULong value3() { +// return getValue(); +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public AccountStatRecord value1(java.lang.Integer value) { +// setAccountId(value); +// return this; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public AccountStatRecord value2(java.lang.Integer value) { +// setStatId(value); +// return this; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public AccountStatRecord value3(org.jooq.types.ULong value) { +// setValue(value); +// return this; +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public AccountStatRecord values(java.lang.Integer value1, java.lang.Integer value2, org.jooq.types.ULong value3) { +// return this; +// } +// +// // ------------------------------------------------------------------------- +// // Constructors +// // ------------------------------------------------------------------------- +// +// /** +// * Create a detached AccountStatRecord +// */ +// public AccountStatRecord() { +// super(mineplex.database.tables.AccountStat.accountStat); +// } +// +// /** +// * Create a detached, initialised AccountStatRecord +// */ +// public AccountStatRecord(java.lang.Integer accountId, java.lang.Integer statId, org.jooq.types.ULong value) { +// super(mineplex.database.tables.AccountStat.accountStat); +// +// setValue(0, accountId); +// setValue(1, statId); +// setValue(2, value); +// } + +} diff --git a/Plugins/Mineplex.EnjinTranslator/src/mineplex/enjinTranslator/Enjin.java b/Plugins/Mineplex.EnjinTranslator/src/mineplex/enjinTranslator/Enjin.java index f9bf43da3..b36ab85d8 100644 --- a/Plugins/Mineplex.EnjinTranslator/src/mineplex/enjinTranslator/Enjin.java +++ b/Plugins/Mineplex.EnjinTranslator/src/mineplex/enjinTranslator/Enjin.java @@ -2,17 +2,13 @@ package mineplex.enjinTranslator; import java.text.SimpleDateFormat; import java.time.LocalDate; -import java.util.AbstractMap; import java.util.Date; -import java.util.Iterator; -import java.util.Map.Entry; import java.util.UUID; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; import mineplex.core.MiniPlugin; import mineplex.core.account.CoreClient; @@ -20,15 +16,12 @@ import mineplex.core.account.CoreClientManager; import mineplex.core.common.Rank; import mineplex.core.common.currency.GlobalCurrency; import mineplex.core.common.util.Callback; -import mineplex.core.common.util.NautHashMap; import mineplex.core.donation.DonationManager; import mineplex.core.inventory.InventoryManager; import mineplex.core.powerplayclub.PowerPlayClubRepository; import mineplex.core.punish.Category; import mineplex.core.punish.Punish; import mineplex.core.server.util.TransactionResponse; -import mineplex.core.updater.UpdateType; -import mineplex.core.updater.event.UpdateEvent; import mineplex.enjinTranslator.purchase.PurchaseManager; public class Enjin extends MiniPlugin implements CommandExecutor @@ -40,7 +33,6 @@ public class Enjin extends MiniPlugin implements CommandExecutor private PowerPlayClubRepository _powerPlayClubRepository; private Punish _punish; - private NautHashMap> _cachedUUIDs = new NautHashMap>(); private static Object _commandLock = new Object(); public long _lastPoll = System.currentTimeMillis() - 120000; @@ -63,21 +55,6 @@ public class Enjin extends MiniPlugin implements CommandExecutor plugin.getCommand("pull").setExecutor(this); } - @EventHandler - public void expireCachedUUIDs(UpdateEvent event) - { - if (event.getType() != UpdateType.MIN_01) - return; - - for (Iterator>> iterator = _cachedUUIDs.entrySet().iterator(); iterator.hasNext(); ) - { - Entry> entry = iterator.next(); - - if (System.currentTimeMillis() > entry.getValue().getValue()) - iterator.remove(); - } - } - @Override public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { @@ -90,35 +67,26 @@ public class Enjin extends MiniPlugin implements CommandExecutor if (label.equalsIgnoreCase("enjin_mineplex")) { - final String name = args[1]; + final UUID uuid; + try + { + uuid = UUID.fromString(args[1]); + } + catch (IllegalArgumentException e) + { + System.out.println("[" + _dateFormat.format(new Date()) + "] ERROR processing " + args[1] + "; invalid UUID."); + return true; + } - _clientManager.loadClientByName(name, client -> + _clientManager.loadClientByUUID(uuid, client -> { if (client == null) { - System.out.println("[" + _dateFormat.format(new Date()) + "] ERROR processing " + name + ", isn't in our database."); + System.out.println("[" + _dateFormat.format(new Date()) + "] ERROR processing " + uuid + ", isn't in our database."); } else { - UUID uuid = null; - - if (_cachedUUIDs.containsKey(name)) - uuid = _cachedUUIDs.get(name).getKey(); - else - { - // Fails if not in DB and if duplicate. - uuid = _clientManager.loadUUIDFromDB(name); - } - - if (uuid == null) - { - System.out.println("[" + _dateFormat.format(new Date()) + "] ERROR processing " + name + ", no UUID."); - return; - } - - final UUID playerUUID = uuid; - - _cachedUUIDs.put(name, new AbstractMap.SimpleEntry(playerUUID, System.currentTimeMillis() + 240000)); + final String name = client.getName(); if (args[0].equalsIgnoreCase("chargeback")) { @@ -129,15 +97,15 @@ public class Enjin extends MiniPlugin implements CommandExecutor if (!checkForClansPurchase(args, name, client)) { - if (!checkForBoosterPurchase(args, name, playerUUID, client)) + if (!checkForBoosterPurchase(args, name, uuid, client)) { - if (!checkForCoinPurchase(args, name, playerUUID, client)) + if (!checkForCoinPurchase(args, name, uuid, client)) { - if (!checkForRankPurchase(args, name, playerUUID, client)) + if (!checkForRankPurchase(args, name, uuid, client)) { if (!checkForPurchase(args, name, client)) { - if (!checkForPowerPlayClub(args, name, playerUUID, client)) + if (!checkForPowerPlayClub(args, name, uuid, client)) { StringBuilder sb = new StringBuilder(); diff --git a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java index bc74ec6f1..29e6ab472 100644 --- a/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java +++ b/Plugins/Mineplex.Hub.Clans/src/mineplex/clanshub/HubManager.java @@ -674,7 +674,7 @@ public class HubManager extends MiniPlugin implements IChatMessageFormatter _lastPlayerCount = playerCount; Bukkit.getOnlinePlayers().stream().filter(player -> _clientManager.Get(player).GetRank() == Rank.ALL).forEach(player -> { - UtilTextBottom.display(C.cGray + "Visit " + F.elem("http://www.mineplex.com/shop") + " for exclusive perks!", player); + UtilTextBottom.display(C.cGray + "Visit " + F.elem("http://www.mineplex.com/shop") + " for exclusive hattori!", player); }); } diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java index a4b0a0b88..6c22d7cbb 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/Hub.java @@ -16,7 +16,7 @@ import mineplex.core.antihack.guardians.GuardianManager; import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.blockrestore.BlockRestore; import mineplex.core.boosters.BoosterManager; -import mineplex.core.brawl.fountain.FountainManager; +import mineplex.hub.brawl.fountain.FountainManager; import mineplex.core.chat.Chat; import mineplex.core.chatsnap.SnapshotManager; import mineplex.core.chatsnap.SnapshotPlugin; @@ -188,7 +188,7 @@ public class Hub extends JavaPlugin implements IRelation QueueManager queueManager = new QueueManager(this, clientManager, donationManager, eloManager, partyManager); ServerManager serverManager = new ServerManager(this, clientManager, donationManager, portal, partyManager, serverStatusManager, hubManager, queueManager, boosterManager); - new FountainManager(this, clientManager, donationManager, hologramManager, statsManager, serverManager); + new FountainManager(this, serverManager); Chat chat = new Chat(this, incognito, clientManager, preferenceManager, achievementManager, serverStatusManager.getCurrentServerName()); new MessageManager(this, incognito, clientManager, preferenceManager, ignoreManager, punish, friendManager, chat); diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java index 51d2ca779..070cd582a 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/HubManager.java @@ -104,6 +104,7 @@ import mineplex.core.preferences.Preference; import mineplex.core.preferences.PreferencesManager; import mineplex.core.projectile.ProjectileManager; import mineplex.core.punish.Punish; +import mineplex.core.quests.QuestManager; import mineplex.core.scoreboard.MineplexScoreboard; import mineplex.core.scoreboard.ScoreboardManager; import mineplex.core.stats.StatsManager; @@ -178,6 +179,7 @@ public class HubManager extends MiniClientPlugin implements IChatMess // private HalloweenSpookinessManager _halloweenManager; // private TrickOrTreatManager _trickOrTreatManager; private MavericksManager _mavericksManager; + private QuestManager _questManager; private final TwoFactorAuth _twofactor = Managers.require(TwoFactorAuth.class); private HologramManager _hologramManager; @@ -291,6 +293,8 @@ public class HubManager extends MiniClientPlugin implements IChatMess _hologramManager = hologramManager; new EasterEggHunt(plugin, _clientManager); + + _questManager = new QuestManager(hologramManager, null, _inventoryManager, _donationManager); new TemporaryGemHuntersServerSender(_portal); @@ -1029,4 +1033,9 @@ public class HubManager extends MiniClientPlugin implements IChatMess { return _jumpManager; } + + public QuestManager getQuestManager() + { + return _questManager; + } } diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/brawl/fountain/FountainManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/brawl/fountain/FountainManager.java new file mode 100644 index 000000000..5bbeb6618 --- /dev/null +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/brawl/fountain/FountainManager.java @@ -0,0 +1,78 @@ +package mineplex.hub.brawl.fountain; + +import java.util.Calendar; +import java.util.TimeZone; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import mineplex.core.MiniPlugin; +import mineplex.core.common.util.F; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.hub.server.ServerManager; + +public class FountainManager extends MiniPlugin +{ + private final ServerManager _serverManager; + private boolean _brawlActive = false; + + public FountainManager(JavaPlugin plugin, ServerManager serverManager) + { + super("Counter", plugin); + _serverManager = serverManager; + } + + @EventHandler + public void updateFountainCount(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + return; + + updateBrawlActive(); + } + + public void updateBrawlActive() + { + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("PST")); + int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); + _brawlActive = dayOfWeek == Calendar.FRIDAY || dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY; + } + + @EventHandler + public void onInteractAtEntity(PlayerInteractAtEntityEvent event) + { + tryBrawl(event.getPlayer(), event.getRightClicked()); + } + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) + { + if (event.getDamager() instanceof Player) + { + tryBrawl((Player) event.getDamager(), event.getEntity()); + } + } + + private void tryBrawl(Player player, Entity entity) + { + if (entity.getCustomName() != null && entity.isCustomNameVisible()) + { + if (entity.getCustomName().contains("Weekend Brawl")) + { + if (_brawlActive) + { + _serverManager.getBrawlShop().attemptShopOpen(player); + } + else + { + player.sendMessage(F.main("BRAWL", "Come back this weekend to play Weekend Brawl!")); + } + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java index cc37b55a6..f833f0200 100644 --- a/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java +++ b/Plugins/Mineplex.Hub/src/mineplex/hub/server/ServerManager.java @@ -29,7 +29,6 @@ import mineplex.core.Managers; import mineplex.core.MiniPlugin; import mineplex.core.account.CoreClientManager; import mineplex.core.boosters.BoosterManager; -import mineplex.core.brawl.fountain.BrawlShopProvider; import mineplex.core.common.Rank; import mineplex.core.common.util.C; import mineplex.core.common.util.Callback; @@ -62,7 +61,7 @@ import mineplex.serverdata.Region; import mineplex.serverdata.data.MinecraftServer; import mineplex.serverdata.data.ServerGroup; -public class ServerManager extends MiniPlugin implements BrawlShopProvider +public class ServerManager extends MiniPlugin { private static final Long FREE_PORTAL_TIMER = -1L; private static final Long BETA_PORTAL_TIMER = 120000L; @@ -858,7 +857,7 @@ public class ServerManager extends MiniPlugin implements BrawlShopProvider public ShopBase getBrawlShop() { - return _serverNpcShopMap.get("Weekend Brawl"); + return _serverNpcShopMap.get("BRAWL"); } public ShopBase getBawkShop() diff --git a/Plugins/Mineplex.MapParser/src/mineplex/mapparser/GameType.java b/Plugins/Mineplex.MapParser/src/mineplex/mapparser/GameType.java index b3b28d303..b8c09946c 100644 --- a/Plugins/Mineplex.MapParser/src/mineplex/mapparser/GameType.java +++ b/Plugins/Mineplex.MapParser/src/mineplex/mapparser/GameType.java @@ -44,6 +44,7 @@ public enum GameType MineWare("MineWare"), MinecraftLeague("MCL"), MilkCow("Milk the Cow"), + HOG("Heroes of GWEN"), MonsterLeague("MonsterLeague"), MonsterMaze("Monster Maze"), Paintball("Super Paintball"), diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/CustomDamageEvent.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/CustomDamageEvent.java index 83d3d0a0c..2ebe4cac2 100644 --- a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/CustomDamageEvent.java +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/damage/CustomDamageEvent.java @@ -100,7 +100,7 @@ public class CustomDamageEvent extends Event implements Cancellable public void AddMod(String source, double mod) { - AddMod(source, new String(), mod, false); + AddMod(source, "", mod, false); } public void AddMod(String source, String reason, double mod, boolean useAttackName) diff --git a/Plugins/Mineplex.ServerData/pom.xml b/Plugins/Mineplex.ServerData/pom.xml index 84a00934c..85d99c4e7 100644 --- a/Plugins/Mineplex.ServerData/pom.xml +++ b/Plugins/Mineplex.ServerData/pom.xml @@ -8,6 +8,10 @@ mineplex-parent dev-SNAPSHOT + + + 18.0 + mineplex-serverdata @@ -33,5 +37,11 @@ jooq 3.5.2 + + com.google.guava + guava + ${version.guava} + compile + diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubJedisClient.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubJedisClient.java new file mode 100644 index 000000000..5a8cfa8a5 --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubJedisClient.java @@ -0,0 +1,356 @@ +package mineplex.serverdata.redis.messaging; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; + +import mineplex.serverdata.Utility; +import mineplex.serverdata.servers.ConnectionData; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.exceptions.JedisDataException; + +/** + * A subscription to a Redis pub/sub system through a Jedis client. Includes a publishing mechanism + * as well. + *

+ * Subscribes to Jedis and offers a variety of methods to edit the channels that this listens to + * over time. Does not support pattern-matching, even though Jedis can. Takes a single subscriber to + * inform of incoming messages (on all channels this is subscribed to). + *

+ * For the sake of internal efficiency, this does not protect the sanity or unchangeability of + * arguments passed into its methods. Clients should not generally interact with this directly. + *

+ * The Jedis pub/sub interface is a little confusing, especially when it comes to multithreading. At + * any given time, if this class is subscribed to any channels at all, it will have a single thread + * that is listening for incoming messages from redis with a blocking method. After that listening + * thread is created, we can add and remove subscriptions as desired, but the initial subscription + * and actual listening must be done on its own thread. When all channels are unsubscribed from, the + * listening thread returns. Note that this is stated with about 70% certainty, as the internals of + * the pub/sub mechanism are not entirely clear to me. + *

+ * This class maintains a constant connection to its redis server by subscribing to a base channel. + * This makes it much easier to protect its operation from potentially insane client commands. + *

+ * If the connection to the given redis instance fails or is interrupted, will keep attempting to + * reconnect periodically until destroyed. Publishers and subscribers are not informed of failure in + * any way. + *

+ * When {@link #unsubscribe()} or {@link #destroy()} is called, this class ceases operation. + */ +public class PubSubJedisClient extends JedisPubSub implements PubSubLibraryClient +{ + + private static final long RECONNECT_PERIOD_MILLIS = 800; + private static final String BASE_CHANNEL = "pG8n5jp#"; + + private static final String BOLD = "\u001B[1m"; + private static final String RESET = "\u001B[0m"; + + private final String _id; + private JedisPool _writePool; + private final ConnectionData _readConn; + private JedisPool _readPool; + private final ExecutorService _threadPool = Executors.newCachedThreadPool(); + private volatile Subscriber _sub; + + private final Set _channels = Collections + .newSetFromMap(new ConcurrentHashMap()); + private final Map> _pendingFutures = new ConcurrentHashMap>(); + + private volatile boolean _subscribed; // Is there a base subscription yet? + private volatile boolean _destroyed; // has this been deliberately destroyed? + + /** + * Class constructor. + * + * @param writeTo The connection info for the redis instance this client should publish to. + * @param readFrom The connection info for the redis instance this client to subscribe to. + */ + public PubSubJedisClient(ConnectionData writeTo, ConnectionData readFrom) + { + if (writeTo == null) + { + throw new IllegalArgumentException("redis connection info cannot be null"); + } + + _id = writeTo.getName(); + _writePool = Utility.generatePool(writeTo); + + _readConn = readFrom; + _readPool = Utility.generatePool(readFrom); + + createSubscription(BASE_CHANNEL); + } + + @Override + public final synchronized void setSubscriber(Subscriber sub) + { + _sub = sub; + } + + @Override + public final ListenableFuture addChannel(String channel) + { + SettableFuture ret = _pendingFutures.get(channel); + if (ret == null) + { + ret = SettableFuture.create(); + _pendingFutures.put(channel, ret); + } + + try + { + _channels.add(channel); + + if (_subscribed) + { // Already has a subscription thread and can just add a new channel to it. + subscribe(channel); + } + } catch (Exception ex) + { + log("Encountered issue subscribing to a channel."); + ex.printStackTrace(); + ret.setException(ex); + } + + return ret; + } + + @Override + public final void removeChannel(String channel) + { + if (BASE_CHANNEL.equals(channel)) + { // Protects the base subscription + return; + } + + _channels.remove(channel); + + if (_subscribed) + { + unsubscribe(channel); + } + } + + @Override + public final void unsubscribe() + { + destroy(); + } + + @Override + public final void destroy() + { + _destroyed = true; + try + { + super.unsubscribe(); + } catch (NullPointerException e) + { + } + + for (SettableFuture fut : _pendingFutures.values()) + { + fut.set(false); + } + } + + @Override + public final void onMessage(String channel, String message) + { + if (_sub == null || BASE_CHANNEL.equals(channel)) + { + return; + } + + try + { + _sub.onMessage(channel, message); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + @Override + public final ListenableFuture publish(final String channel, final String message) + { + final SettableFuture ret = SettableFuture.create(); + _threadPool.execute(new Runnable() + { + @Override + public void run() + { + Jedis bJedis = null; + try + { + bJedis = _writePool.getResource(); + bJedis.publish(channel, message); + _writePool.returnResource((Jedis) bJedis); + ret.set(true); + + } catch (Exception e) + { + log("Encountered issue while publishing a message."); + e.printStackTrace(); + if (bJedis != null) + { + _writePool.returnBrokenResource((Jedis) bJedis); + } + ret.set(false); + } + } + }); + return ret; + } + + // Confirms successful subscriptions/unsubscriptions. + @Override + public void onSubscribe(String channel, int subscribedChannels) + { + + // informs subscriber that this subscription completed successfully + SettableFuture fut = _pendingFutures.remove(channel); + if (fut != null) + { + fut.set(true); + } + + if (!_subscribed) + { + for (String subscribeTo : _channels) + { + subscribe(subscribeTo); + } + } + _subscribed = true; + + log("Subscribed to channel: " + channel); + } + + @Override + public void onUnsubscribe(String channel, int subscribedChannels) + { + log("Unsubscribed from channel: " + channel); + } + + /** + * Creates the initial listening thread which blocks as it polls redis for new messages. + * Subsequent subscriptions can simply be added using {@link #subscribe(String...)} after the + * subscription thread has been created. + * + * @param firstChannel The first channel to initially subscribe to. If you do not have a first + * channel, there is no reason to create a subscriber thread yet. + */ + private void createSubscription(final String firstChannel) + { + + final JedisPubSub pubsub = this; + + new Thread(new Runnable() + { + @Override + public void run() + { + + boolean first = true; + + while (!_destroyed) + { + + if (!first) + { + log("Jedis connection to " + _readConn.getHost() + ":" + + _readConn.getPort() + + " failed or was interrupted, attempting to reconnect"); + } + first = false; + + Jedis jedisInstance = null; + + try + { + // gets a non-thread-safe jedis instance from the thread-safe pool. + jedisInstance = _readPool.getResource(); + + log("Creating initial jedis subscription to channel " + firstChannel); + // this will block as long as there are subscriptions + jedisInstance.subscribe(pubsub, firstChannel); + + log("jedisInstance.subscribe() returned, subscription over."); + + // when the subscription ends (subscribe() returns), returns the instance to + // the pool + _readPool.returnResource(jedisInstance); + + } catch (JedisConnectionException e) + { + log("Jedis connection encountered an issue."); + e.printStackTrace(); + if (jedisInstance != null) + { + _readPool.returnBrokenResource((Jedis) jedisInstance); + } + + } catch (JedisDataException e) + { + log("Jedis connection encountered an issue."); + e.printStackTrace(); + if (jedisInstance != null) + { + _readPool.returnBrokenResource((Jedis) jedisInstance); + } + } + _subscribed = false; + + // sleeps for a short pause, rather than constantly retrying connection + if (!_destroyed) + { + try + { + Thread.sleep(RECONNECT_PERIOD_MILLIS); + } catch (InterruptedException e) + { + _destroyed = true; + log("Reconnection pause thread was interrupted."); + e.printStackTrace(); + } + } + } + } + }).start(); + } + + // This implementation does not support pattern-matching subscriptions + @Override + public void onPMessage(String pattern, String channel, String message) + { + } + + @Override + public void onPSubscribe(String pattern, int subscribedChannels) + { + } + + @Override + public void onPUnsubscribe(String pattern, int subscribedChannels) + { + } + + private void log(String msg) + { + System.out.println(BOLD + "[" + getClass().getSimpleName() + + (_id != null && !_id.isEmpty() ? " " + _id : "") + "] " + RESET + msg); + } + +} diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubLibraryClient.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubLibraryClient.java new file mode 100644 index 000000000..4a9f2820c --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubLibraryClient.java @@ -0,0 +1,61 @@ +package mineplex.serverdata.redis.messaging; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * A multi-channel subscription and publisher to a pub/sub messaging implementation. An interface to + * the actual low-level pub/sub library, whatever it may be. + * + * For the sake of internal efficiency, this makes no guarantees for the sanity or unchangeability + * of arguments passed into its methods. Clients should not generally interact with this directly. + */ +public interface PubSubLibraryClient +{ + + /** + * Publishes a message to all subscribers of a given channel. + * + * @param channel The channel to publish the message on. + * @param message The message to send. + * @return A future object that will complete after an unknown amount of time with + * false if for some locally known reason the message definitely could not + * be published, else completes with true. + */ + ListenableFuture publish(String channel, String message); + + /** + * Adds a channel to this subscription. + * + * @param channel The channel to add. Should not change after being passed in. + * @return The asynchronous, future result of this attempt to add the channel. Will have + * true when the subscription starts successfully. + */ + ListenableFuture addChannel(String channel); + + /** + * Removes a channel from this subscription. + * + * @param channel The channel to remove. Should not change after being passed in. + */ + void removeChannel(String channel); + + /** + * Removes all channels from this subscription, kills its connections, and relinquishes any + * resources it was occupying. + *

+ * Depending on the implementation, once a subscription has been destroyed, it may not be + * reusable and it may be necessary to construct a new one in order to resume. + *

+ * Call this when the subscription is no longer being used. Holding unnecessary connections can + * cause serious performance and other issues on both ends. + */ + void destroy(); + + /** + * Sets the subscriber to inform of messages received by this subscription. + * + * @param sub The listener for this subscription. + */ + void setSubscriber(Subscriber sub); + +} diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubMessager.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubMessager.java new file mode 100644 index 000000000..ea45109e1 --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubMessager.java @@ -0,0 +1,56 @@ +package mineplex.serverdata.redis.messaging; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Messager for standard pub/sub model. Handles multiple publishers and subscribers. + *

+ * All messaging is asynchronous and non-blocking, even to local subscribers. + *

+ * For more about the pub/sub messaging paradigm, see http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern + */ +public interface PubSubMessager +{ + + /** + * Publishes a message to all subscribers of a given channel. + *

+ * Publishes to all connected subscribers, including local ones. + * + * @param channel The channel to publish the message on. + * @param message The message to send. + * @return A future object that will complete after an unknown amount of time with + * false if for some locally known reason the message definitely could not + * be published, else completes with true (which does not guarantee it + * succeeded 100%). + */ + ListenableFuture publish(String channel, String message); + + /** + * Subscribes to a messaging channel. + *

+ * When incoming messages arrive, the subscriber is called from an arbitrary new thread. + * + * @param channel The channel to subscribe to. + * @param sub The subscriber to inform of incoming messages. + * @return The asynchronous, future result of this attempt to subscribe to the channel. Will + * have true when the subscription starts successfully. + */ + ListenableFuture subscribe(String channel, Subscriber sub); + + /** + * Unsubscribes from a messaging channel. + * + * @param channel The channel to unsubscribe from. + * @param sub The subscriber to stop informing of incoming messages. + */ + void unsubscribe(String channel, Subscriber sub); + + /** + * Attempts to gracefully shut down this messager. Generally irreversible. + */ + void shutdown(); + +} diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubRouter.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubRouter.java new file mode 100644 index 000000000..453b90743 --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/PubSubRouter.java @@ -0,0 +1,165 @@ +package mineplex.serverdata.redis.messaging; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; + +/** + * A pub/sub messager that simply routes messages to some underlying pub/sub implementation, which + * is in turn represented by a multi-channel subscription and a publishing mechanism. + *

+ * This class handles: + *

    + *
  1. Providing a modular messaging interface that is thread-safe. + *
  2. Protecting pub/sub implementations from some bad client behavior/data. + *
  3. Routing messages for multiple subscribers to the same channel(s). + *
+ */ +public class PubSubRouter implements PubSubMessager, Subscriber +{ + + private final PubSubLibraryClient _pubSubClient; + private final Map> _subscribers; + + private final ExecutorService _threadPool; + + public PubSubRouter(PubSubLibraryClient client) + { + if (client == null) + { + throw new IllegalArgumentException("pubsub client cannot be null"); + } + + this._pubSubClient = client; + this._pubSubClient.setSubscriber(this); + this._subscribers = new ConcurrentHashMap>(); + + this._threadPool = Executors.newCachedThreadPool(); + } + + @Override + public final ListenableFuture publish(String channel, String message) + { + if (channel == null || channel.isEmpty()) + { + throw new IllegalArgumentException("channel cannot be null or empty"); + } + + // messages of 0 length are allowed. Null messages are treated as messages of 0 length. + if (message == null) + { + message = ""; + } + + return _pubSubClient.publish(channel, message); + } + + @Override + public final ListenableFuture subscribe(String channel, Subscriber sub) + { + if (channel == null || channel.isEmpty() || sub == null) + { + throw new IllegalArgumentException("params cannot be null and channel cannot be empty"); + } + + ListenableFuture ret = null; + + Set channelSubs = _subscribers.get(channel); + if (channelSubs == null) + { + // uses CopyOnWriteArraySet for fast and consistent iteration (forwarding messages to + // subscribers) but slow writes (adding/removing subscribers). + // See a discussion of the issue here: + // http://stackoverflow.com/questions/6720396/different-types-of-thread-safe-sets-in-java + channelSubs = new CopyOnWriteArraySet(); + _subscribers.put(channel, channelSubs); + + // starts a jedis subscription to the channel if there were no subscribers before + ret = _pubSubClient.addChannel(channel); + + } else + { + ret = SettableFuture.create(); + ((SettableFuture) ret).set(true); // already subscribed, calls back immediately + } + + channelSubs.add(sub); + + return ret; + } + + @Override + public final void unsubscribe(String channel, Subscriber sub) + { + if (channel == null || channel.isEmpty() || sub == null) + { + throw new IllegalArgumentException("params cannot be null and channel cannot be empty"); + } + + Set channelSubs = _subscribers.get(channel); + if (channelSubs == null) + { // no subscribers for the channel to begin with. + return; + } + + channelSubs.remove(sub); + + // stops the subscription to this channel if the unsubscribed was the last subscriber + if (channelSubs.isEmpty()) + { + _subscribers.remove(channel); + _pubSubClient.removeChannel(channel); + } + } + + @Override + public final void onMessage(final String channel, final String message) + { + if (channel == null || message == null || channel.isEmpty()) + { + return; + } + + Set channelSubs = _subscribers.get(channel); + + if (channelSubs == null) + { // We should not still be listening + _pubSubClient.removeChannel(channel); + return; + } else if (channelSubs.isEmpty()) + { + _subscribers.remove(channel); + _pubSubClient.removeChannel(channel); + return; + } + + for (final Subscriber sub : channelSubs) + { + + // Gives subscribers their own thread from the thread pool in which to react to the + // message. + // Avoids interruptions and other problems while iterating over the subscriber set. + _threadPool.execute(new Runnable() + { + @Override + public void run() + { + sub.onMessage(channel, message); + } + }); + } + } + + @Override + public void shutdown() + { + _pubSubClient.destroy(); + } + +} diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/Subscriber.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/Subscriber.java new file mode 100644 index 000000000..5ecc09796 --- /dev/null +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/messaging/Subscriber.java @@ -0,0 +1,19 @@ +package mineplex.serverdata.redis.messaging; + +/** + * A subscriber to a pub/sub channel. + */ +public interface Subscriber +{ + + /** + * Called when a message is sent on a channel that this is subscribed to. + *

+ * No guarantees are made about what thread this will be called from. + * + * @param channel The channel that the message was sent on. + * @param message The message that was received. + */ + void onMessage(String channel, String message); + +} diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java index dceba28ab..d9e82ba75 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/CustomerSupport.java @@ -6,7 +6,6 @@ import java.time.LocalDate; import java.time.YearMonth; import java.time.format.TextStyle; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -54,7 +53,6 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable private CustomerSupportRepository _repository; private PowerPlayClubRepository _powerPlayRepo; - private NautHashMap> _agentCacheMap = new NautHashMap>(); private NautHashMap> _accountBonusLog = new NautHashMap<>(); private boolean _allowWeatherChange = false; @@ -72,6 +70,10 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable _allowWeatherChange = true; Bukkit.getWorlds().get(0).setStorm(false); _allowWeatherChange = false; + + addCommand(new checkCommand(this)); + addCommand(new checkOwnsPackageCommand(this)); + addCommand(new ListPPCCommand(this, _powerPlayRepo)); } @EventHandler @@ -100,27 +102,12 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable event.setFormat(C.cGold + "%1$s " + C.cWhite + "%2$s"); } - - @Override - public void addCommands() - { - addCommand(new checkCommand(this)); - addCommand(new checkOwnsPackageCommand(this)); - } public void Help(Player caller) { caller.sendMessage(F.main(getName(), "Usage : /check defek7")); } - public void addAgentMapping(Player caller, CoreClient client) - { - if (!_agentCacheMap.containsKey(caller)) - _agentCacheMap.put(caller, new HashSet()); - - _agentCacheMap.get(caller).add(client.getName()); - } - public void showPlayerInfo(Player caller, CoreClient client) { String playerName = client.getName(); @@ -473,12 +460,6 @@ public class CustomerSupport extends MiniPlugin implements ResultSetCallable event.setCancelled(true); } - @EventHandler - public void removeMapping(PlayerQuitEvent event) - { - _agentCacheMap.remove(event.getPlayer()); - } - @EventHandler public void foodLevelChange(FoodLevelChangeEvent event) { diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/ListPPCCommand.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/ListPPCCommand.java new file mode 100644 index 000000000..6d3c1243a --- /dev/null +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/ListPPCCommand.java @@ -0,0 +1,117 @@ +package mineplex.staffServer.customerSupport; + +import java.time.YearMonth; +import java.time.format.TextStyle; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import mineplex.core.command.CommandBase; +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.powerplayclub.PowerPlayClubRepository; +import mineplex.core.powerplayclub.PowerPlayClubRewards; +import mineplex.core.powerplayclub.PowerPlayData; + +public class ListPPCCommand extends CommandBase +{ + private final PowerPlayClubRepository _powerPlayRepo; + + public ListPPCCommand(CustomerSupport customerSupport, PowerPlayClubRepository powerPlayRepo) + { + super(customerSupport, Rank.MODERATOR, "listppc", "checkppc"); + _powerPlayRepo = powerPlayRepo; + } + + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Usage: /" + _aliasUsed + " ")); + return; + } + + _commandCenter.GetClientManager().checkPlayerName(caller, args[0], name -> + { + if (name != null) + { + _commandCenter.GetClientManager().loadClientByName(name, client -> + { + if (client == null) + { + UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not load data for " + name)); + return; + } + + PowerPlayData powerPlayData = _powerPlayRepo.loadData(client.getAccountId()).join(); + Inventory inventory = buildPPCDisplay(client.getName(), powerPlayData); + caller.openInventory(inventory); + }); + } + }); + } + + private static Inventory buildPPCDisplay(String playerName, PowerPlayData data) + { + Inventory result = Bukkit.createInventory(null, Math.max(1, (int)Math.ceil(data.getSubscriptions().size() / 9D)) * 9, playerName + "'s Subscriptions"); + data.getSubscriptions().stream().map(sub -> buildSubDisplay(data, sub)).forEach(result::addItem); + return result; + } + + private static ItemStack buildSubDisplay(PowerPlayData data, PowerPlayData.Subscription sub) + { + PowerPlayData dataForSubscription = PowerPlayData.fromSubsAndClaims(Collections.singletonList(sub), Collections.emptyList()); + dataForSubscription.getUnclaimedMonths().removeIf(yearMonth -> !data.getUnclaimedMonths().contains(yearMonth)); + + boolean claimed = dataForSubscription.getUnclaimedMonths().isEmpty(); + + List lore = new ArrayList<>(); + lore.add(C.cYellow + "Start date: " + C.cWhite + sub._startDate.getMonth().getDisplayName(TextStyle.SHORT, Locale.US) + " " + sub._startDate.getDayOfMonth() + " " + sub._startDate.getYear()); + lore.add(C.cYellow + "Duration: " + C.cWhite + sub._duration.name()); + lore.add(" "); + lore.add(C.cGreen + "Subscription Cosmetics"); + PowerPlayClubRewards.rewards().entrySet().stream() + .filter(entry -> dataForSubscription.getUsableCosmeticMonths().contains(entry.getKey())) + .sorted(Comparator.comparing(Map.Entry::getKey)) + .forEach(entry -> + { + YearMonth yearMonth = entry.getKey(); + lore.add(C.cWhite + " " + entry.getValue().getPrizeName() + " " + C.cGold + yearMonth.getMonth().getDisplayName(TextStyle.SHORT, Locale.US) + " " + yearMonth.getYear()); + }); + + lore.add(" "); + + if (claimed) + { + lore.add(C.cYellow + "All current rewards claimed"); + } + else + { + lore.add(C.cRed + "Unclaimed rewards"); + lore.add(" " + C.cWhite + (PowerPlayClubRewards.AMPLIFIERS_PER_MONTH * dataForSubscription.getUnclaimedMonths().size()) + " Game Amplifier"); + lore.add(" " + C.cWhite + (PowerPlayClubRewards.CHESTS_PER_MONTH * dataForSubscription.getUnclaimedMonths().size()) + " Omega Chest"); + } + + ItemStack stack = new ItemStack(claimed ? Material.IRON_BLOCK : Material.GOLD_BLOCK); + ItemMeta meta = stack.getItemMeta(); + + meta.setDisplayName(C.cWhite + "Subscription"); + meta.setLore(lore); + + stack.setItemMeta(meta); + return stack; + } +} diff --git a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/checkCommand.java b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/checkCommand.java index 62017cba3..d4d2542e6 100644 --- a/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/checkCommand.java +++ b/Plugins/Mineplex.StaffServer/src/mineplex/staffServer/customerSupport/checkCommand.java @@ -1,12 +1,11 @@ package mineplex.staffServer.customerSupport; -import mineplex.core.common.util.F; -import mineplex.core.common.util.UtilPlayer; import org.bukkit.entity.Player; import mineplex.core.command.CommandBase; import mineplex.core.common.Rank; -import mineplex.core.common.util.Callback; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilPlayer; public class checkCommand extends CommandBase { @@ -35,7 +34,6 @@ public class checkCommand extends CommandBase if (client != null) { Plugin.showPlayerInfo(caller, client); - Plugin.addAgentMapping(caller, client); } else { diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java index 7eb6eee04..197d76ff0 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/Arcade.java @@ -394,4 +394,9 @@ public class Arcade extends JavaPlugin config.GameModeMods.get(mode).put(var, value); } } + + public ServerConfiguration getServerConfig() + { + return _serverConfiguration; + } } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java index 4806f141f..bdca5e21c 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/ArcadeManager.java @@ -94,6 +94,7 @@ import mineplex.core.preferences.PreferencesManager; import mineplex.core.progression.KitProgressionManager; import mineplex.core.projectile.ProjectileManager; import mineplex.core.punish.Punish; +import mineplex.core.quests.QuestManager; import mineplex.core.rankGiveaway.eternal.EternalGiveawayManager; import mineplex.core.rankGiveaway.titangiveaway.TitanGiveawayManager; import mineplex.core.resourcepack.ResourcePackManager; @@ -233,8 +234,8 @@ public class ArcadeManager extends MiniPlugin implements IRelation private ScoreboardManager _scoreboardManager; private NextBestGameManager _nextBestGameManager; private TrackManager _trackManager; + private QuestManager _questManager; private GoogleSheetsManager _sheetsManager; - private IncognitoManager _incognitoManager; private TaskManager _taskManager; @@ -390,6 +391,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation _kitProgressionManager = new KitProgressionManager(getPlugin(), donationManager, clientManager); _progressionKitManager = new ProgressingKitManager(this); _serverUptimeManager = new ServerUptimeManager(this); + _questManager = new QuestManager(hologramManager, _gameLobbyManager.getMissions(), _inventoryManager, _donationManager); if (GetHost() != null && !GetHost().isEmpty() && !GetHost().startsWith("COM-")) { @@ -417,6 +419,11 @@ public class ArcadeManager extends MiniPlugin implements IRelation @Override public void handlePlayerJoin(String playerName) { + if (GetGame() != null && GetGame().GetState() != GameState.Loading && GetGame().GetState() != GameState.Recruit && GetGame().UseCustomScoreboard) + { + return; + } + CoreClient client = GetClients().Get(playerName); for (MineplexScoreboard scoreboard : getScoreboards().values()) @@ -1223,6 +1230,7 @@ public class ArcadeManager extends MiniPlugin implements IRelation player.setGameMode(GameMode.SURVIVAL); player.setAllowFlight(false); player.setFlySpeed(0.1F); + player.setWalkSpeed(0.2F); UtilInv.Clear(player); @@ -2067,16 +2075,21 @@ public class ArcadeManager extends MiniPlugin implements IRelation public TrackManager getTrackManager() { - return this._trackManager; + return _trackManager; } public Titles getTitles() { - return this._titles; + return _titles; + } + + public QuestManager getQuestManager() + { + return _questManager; } public GoogleSheetsManager getSheetsManager() { return _sheetsManager; } -} +} \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/GameType.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/GameType.java index 27c8bde8c..ac4f37774 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/GameType.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/GameType.java @@ -1,14 +1,11 @@ package nautilus.game.arcade; -import nautilus.game.arcade.game.games.alieninvasion.AlienInvasion; -import nautilus.game.arcade.game.games.smash.SuperSmashTraining; -import org.bukkit.Material; - import mineplex.core.common.MinecraftVersion; import mineplex.core.common.Pair; import mineplex.core.game.GameCategory; import mineplex.core.game.GameDisplay; import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.games.alieninvasion.AlienInvasion; import nautilus.game.arcade.game.games.baconbrawl.BaconBrawl; import nautilus.game.arcade.game.games.barbarians.Barbarians; import nautilus.game.arcade.game.games.basketball.Basketball; @@ -65,6 +62,7 @@ import nautilus.game.arcade.game.games.minecraftleague.MinecraftLeague; import nautilus.game.arcade.game.games.minestrike.Minestrike; import nautilus.game.arcade.game.games.minestrike.modes.SuperPaintstrike; import nautilus.game.arcade.game.games.mineware.BawkBawkBattles; +import nautilus.game.arcade.game.games.moba.Moba; import nautilus.game.arcade.game.games.monsterleague.MonsterLeague; import nautilus.game.arcade.game.games.monstermaze.MonsterMaze; import nautilus.game.arcade.game.games.oldmineware.OldMineWare; @@ -93,6 +91,7 @@ import nautilus.game.arcade.game.games.skywars.modes.SkySmash; import nautilus.game.arcade.game.games.skywars.modes.UHCSkywars; import nautilus.game.arcade.game.games.smash.SoloSuperSmash; import nautilus.game.arcade.game.games.smash.SuperSmashDominate; +import nautilus.game.arcade.game.games.smash.SuperSmashTraining; import nautilus.game.arcade.game.games.smash.TeamSuperSmash; import nautilus.game.arcade.game.games.smash.modes.RandomKitSSM; import nautilus.game.arcade.game.games.snake.Snake; @@ -124,6 +123,7 @@ import nautilus.game.arcade.game.games.valentines.Valentines; import nautilus.game.arcade.game.games.wither.WitherGame; import nautilus.game.arcade.game.games.wizards.Wizards; import nautilus.game.arcade.game.games.zombiesurvival.ZombieSurvival; +import org.bukkit.Material; public enum GameType { @@ -232,6 +232,8 @@ public enum GameType AlienInvasion(AlienInvasion.class, GameDisplay.AlienInvasion), + MOBA(Moba.class, GameDisplay.MOBA), + Event(EventGame.class, GameDisplay.Event, new GameType[]{ GameType.BaconBrawl, GameType.Barbarians, GameType.Bridge, GameType.Build, GameType.Build, GameType.Cards, GameType.CastleSiege, GameType.ChampionsDominate, GameType.ChampionsTDM, GameType.Christmas, diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/events/ChestRefillEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/events/ChestRefillEvent.java new file mode 100644 index 000000000..ed2f18fff --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/events/ChestRefillEvent.java @@ -0,0 +1,55 @@ +package nautilus.game.arcade.events; + +import java.util.ArrayList; + +import org.bukkit.Location; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * ChestRefillEvent + * + * @author xXVevzZXx + */ +public class ChestRefillEvent extends Event implements Cancellable +{ + private static final HandlerList handlers = new HandlerList(); + + private boolean _cancelled = false; + + private ArrayList _chests; + + public ChestRefillEvent(ArrayList chests) + { + _chests = (ArrayList) chests.clone(); + } + + public ArrayList getChests() + { + return _chests; + } + + public HandlerList getHandlers() + { + return handlers; + } + + public static HandlerList getHandlerList() + { + return handlers; + } + + @Override + public boolean isCancelled() + { + return _cancelled; + } + + @Override + public void setCancelled(boolean cancelled) + { + _cancelled = cancelled; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java index 80329fe3f..d3fba95de 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/Game.java @@ -18,6 +18,8 @@ import mineplex.core.lifetimes.ListenerComponent; import mineplex.core.lifetimes.PhasedLifetime; import mineplex.core.packethandler.IPacketHandler; import mineplex.core.packethandler.PacketInfo; +import mineplex.core.quests.QuestManager; +import mineplex.core.quests.event.QuestInteractEvent; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import mineplex.core.utils.UtilGameProfile; @@ -39,6 +41,14 @@ import nautilus.game.arcade.game.modules.Module; import nautilus.game.arcade.kit.*; import nautilus.game.arcade.managers.chat.ChatStatData; import nautilus.game.arcade.managers.lobby.LobbyManager; +import nautilus.game.arcade.quest.ChestOpenQuestTracker; +import nautilus.game.arcade.quest.CollectQuestTracker; +import nautilus.game.arcade.quest.KillEntityQuestTracker; +import nautilus.game.arcade.quest.KillQuestTracker; +import nautilus.game.arcade.quest.ParticipateQuestTracker; +import nautilus.game.arcade.quest.PlayGameQuestTracker; +import nautilus.game.arcade.quest.QuestTracker; +import nautilus.game.arcade.quest.WinQuestTracker; import nautilus.game.arcade.scoreboard.GameScoreboard; import nautilus.game.arcade.stats.*; import nautilus.game.arcade.wineffect.WinEffectManager; @@ -135,6 +145,7 @@ public abstract class Game extends ListenerComponent implements Lifetimed // Scoreboard protected GameScoreboard Scoreboard; + public boolean UseCustomScoreboard = false; // Loaded from Map Config public WorldData WorldData = null; @@ -217,7 +228,6 @@ public abstract class Game extends ListenerComponent implements Lifetimed public int HealthSet = -1; public boolean SpawnTeleport = true; - public boolean PrepareFreeze = true; private double _itemMergeRadius = 0; @@ -253,7 +263,10 @@ public abstract class Game extends ListenerComponent implements Lifetimed public boolean AllowParticles = true; + public boolean Prepare = true; public long PrepareTime = 9000; + public boolean PrepareFreeze = true; + public boolean PrepareAutoAnnounce = true; public boolean PlaySoundGameStart = true; public double XpMult = 1; @@ -341,6 +354,7 @@ public abstract class Game extends ListenerComponent implements Lifetimed private NautHashMap _deadBodiesExpire = new NautHashMap(); private final Set> _statTrackers = new HashSet<>(); + private final Set> _questTrackers = new HashSet<>(); private NautHashMap _teamReqs = new NautHashMap(); public WinEffectManager WinEffectManager = new WinEffectManager(); @@ -413,6 +427,16 @@ public abstract class Game extends ListenerComponent implements Lifetimed registerStatTrackers(new KillsStatTracker(this), new DeathsStatTracker(this), new AssistsStatTracker(this), new ExperienceStatTracker(this), new WinStatTracker(this), new LoseStatTracker(this), new DamageDealtStatTracker( this), new DamageTakenStatTracker(this), new GamesPlayedStatTracker(this)); + + // Quest Trackers + registerQuestTrackers( + new WinQuestTracker(this), + new KillQuestTracker(this), + new CollectQuestTracker(this), + new ChestOpenQuestTracker(this), + new KillEntityQuestTracker(this), + new PlayGameQuestTracker(this), + new ParticipateQuestTracker(this)); Manager.getResourcePackManager().setResourcePack(gameType.getResourcePackUrls(this), gameType.isEnforceResourcePack(this)); @@ -1736,6 +1760,20 @@ public abstract class Game extends ListenerComponent implements Lifetimed { return _statTrackers; } + + public void registerQuestTrackers(QuestTracker... questTrackers) + { + for (QuestTracker tracker : questTrackers) + { + if (_questTrackers.add(tracker)) + Bukkit.getPluginManager().registerEvents(tracker, Manager.getPlugin()); + } + } + + public Collection> getQuestTrackers() + { + return _questTrackers; + } @EventHandler public void onHangingBreak(HangingBreakEvent event) @@ -2010,6 +2048,13 @@ public abstract class Game extends ListenerComponent implements Lifetimed ((CraftEntity) event.getEntity()).getHandle().dead = false; } } + + @EventHandler + public void onQuestBuy(QuestInteractEvent event) + { + if (GetState() == GameState.Live || GetState() == GameState.Prepare || GetState() == GameState.End) + event.setCancelled("You cant interact with " + QuestManager.QUEST_NAME + "s while you are ingame!"); + } public NautHashMap getDeadBodies() { @@ -2323,6 +2368,7 @@ public abstract class Game extends ListenerComponent implements Lifetimed Managers.get(AntiHack.class).resetIgnoredChecks(); getLifetime().end(); getStatTrackers().forEach(HandlerList::unregisterAll); + getQuestTrackers().forEach(HandlerList::unregisterAll); } @EventHandler diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/CapturePoint.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/CapturePoint.java index 43709f165..08df99c66 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/CapturePoint.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/CapturePoint.java @@ -1,71 +1,71 @@ -package nautilus.game.arcade.game.games.castleassault.data; - -import org.bukkit.Location; -import org.bukkit.entity.Player; - -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilTime; -import nautilus.game.arcade.game.GameTeam; - -public class CapturePoint -{ - private static final int POINTS_TO_CAPTURE = 100; - private static final long TIME_PER_POINT = 1000; - private static final int POINTS_PER_TICK = 1; - - private Location _loc; - - private long _lastCap; - private int _points = 0; - private GameTeam _owner = null; - - public CapturePoint(GameTeam owner, Location loc) - { - _owner = owner; - - _loc = loc; - } - - public int getMaxPoints() - { - return POINTS_TO_CAPTURE; - } - - public int getPoints() - { - return _points; - } - - public boolean isCaptured() - { - return _points >= POINTS_TO_CAPTURE; - } - - public void update() - { - if (!UtilTime.elapsed(_lastCap, TIME_PER_POINT)) - { - return; - } - - int capping = 0; - for (Player player : UtilPlayer.getInRadius(_loc, 3.5).keySet()) - { - if (UtilPlayer.isSpectator(player)) - { - continue; - } - if (_owner.HasPlayer(player)) - { - continue; - } - capping++; - } - - if (capping > 0 && _points < POINTS_TO_CAPTURE) - { - _lastCap = System.currentTimeMillis(); - _points += POINTS_PER_TICK; - } - } +package nautilus.game.arcade.game.games.castleassault.data; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import nautilus.game.arcade.game.GameTeam; + +public class CapturePoint +{ + private static final int POINTS_TO_CAPTURE = 100; + private static final long TIME_PER_POINT = 1000; + private static final int POINTS_PER_TICK = 1; + + private Location _loc; + + private long _lastCap; + private int _points = 0; + private GameTeam _owner = null; + + public CapturePoint(GameTeam owner, Location loc) + { + _owner = owner; + + _loc = loc; + } + + public int getMaxPoints() + { + return POINTS_TO_CAPTURE; + } + + public int getPoints() + { + return _points; + } + + public boolean isCaptured() + { + return _points >= POINTS_TO_CAPTURE; + } + + public void update() + { + if (!UtilTime.elapsed(_lastCap, TIME_PER_POINT)) + { + return; + } + + int capping = 0; + for (Player player : UtilPlayer.getInRadius(_loc, 3.5).keySet()) + { + if (UtilPlayer.isSpectator(player)) + { + continue; + } + if (_owner.HasPlayer(player)) + { + continue; + } + capping++; + } + + if (capping > 0 && _points < POINTS_TO_CAPTURE) + { + _lastCap = System.currentTimeMillis(); + _points += POINTS_PER_TICK; + } + } } \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/KillStreakData.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/KillStreakData.java index 1e86d8266..571c2039b 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/KillStreakData.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/KillStreakData.java @@ -1,47 +1,47 @@ -package nautilus.game.arcade.game.games.castleassault.data; - -public class KillStreakData -{ - private static final int[] REWARDED_STREAKS = {2, 4, 6, 8}; - private int _kills; - private int _bestStreak; - - public KillStreakData() - { - _kills = 0; - _bestStreak = 0; - } - - public int getKills() - { - return _kills; - } - - public int getBestStreak() - { - return Math.max(_bestStreak, _kills); - } - - public boolean addKill(boolean hardLine) - { - _kills++; - for (int streak : REWARDED_STREAKS) - { - if ((_kills + (hardLine ? 1 : 0)) == streak) - { - return true; - } - } - - return false; - } - - public void reset() - { - if (_kills > _bestStreak) - { - _bestStreak = _kills; - } - _kills = 0; - } +package nautilus.game.arcade.game.games.castleassault.data; + +public class KillStreakData +{ + private static final int[] REWARDED_STREAKS = {2, 4, 6, 8}; + private int _kills; + private int _bestStreak; + + public KillStreakData() + { + _kills = 0; + _bestStreak = 0; + } + + public int getKills() + { + return _kills; + } + + public int getBestStreak() + { + return Math.max(_bestStreak, _kills); + } + + public boolean addKill(boolean hardLine) + { + _kills++; + for (int streak : REWARDED_STREAKS) + { + if ((_kills + (hardLine ? 1 : 0)) == streak) + { + return true; + } + } + + return false; + } + + public void reset() + { + if (_kills > _bestStreak) + { + _bestStreak = _kills; + } + _kills = 0; + } } \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/ObjectiveTNTSpawner.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/ObjectiveTNTSpawner.java index 076913cf1..ec9f86e58 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/ObjectiveTNTSpawner.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/ObjectiveTNTSpawner.java @@ -1,100 +1,100 @@ -package nautilus.game.arcade.game.games.castleassault.data; - -import java.util.List; - -import org.bukkit.Color; -import org.bukkit.FireworkEffect.Type; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Item; -import org.bukkit.inventory.ItemStack; - -import mineplex.core.common.util.UtilFirework; -import mineplex.core.common.util.UtilMath; -import mineplex.core.common.util.UtilTime; - -public class ObjectiveTNTSpawner -{ - private static final long TNT_SPAWN_DELAY = 60000; - private List _locs; - private Location _lastSpawnLoc; - private Item _entity; - private long _lastPickedUp; - - public ObjectiveTNTSpawner(List locs) - { - _locs = locs; - _lastSpawnLoc = null; - _entity = null; - _lastPickedUp = System.currentTimeMillis(); - } - - public Item getItem() - { - return _entity; - } - - public boolean isSpawned() - { - return _entity != null; - } - - public boolean canPlaceFireAt(Block block) - { - for (Location loc : _locs) - { - if (UtilMath.offsetSquared(loc, block.getLocation()) <= 9) - { - return false; - } - } - - return true; - } - - public long getNextTNT() - { - return (_lastPickedUp + TNT_SPAWN_DELAY) - System.currentTimeMillis(); - } - - public void spawn() - { - Location spawn = _locs.get(UtilMath.r(_locs.size())); - spawn.getBlock().getRelative(BlockFace.DOWN).setType(Material.REDSTONE_BLOCK); - _lastSpawnLoc = spawn.clone(); - _entity = spawn.getWorld().dropItem(spawn, new ItemStack(Material.TNT)); - UtilFirework.playFirework(spawn, Type.BURST, Color.RED, false, false); - } - - public void pickup() - { - _entity.getLocation().getBlock().getRelative(BlockFace.DOWN).setType(Material.IRON_BLOCK); - _entity.remove(); - _entity = null; - _lastSpawnLoc = null; - _lastPickedUp = System.currentTimeMillis(); - } - - public void update() - { - if (!isSpawned() && UtilTime.elapsed(_lastPickedUp, TNT_SPAWN_DELAY)) - { - spawn(); - } - else if (isSpawned()) - { - _entity.teleport(_lastSpawnLoc); - if (!_entity.isValid() || _entity.isDead()) - { - _entity = _lastSpawnLoc.getWorld().dropItem(_lastSpawnLoc, new ItemStack(Material.TNT)); - } - } - } - - public void onStart() - { - _lastPickedUp = System.currentTimeMillis(); - } +package nautilus.game.arcade.game.games.castleassault.data; + +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; + +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; + +public class ObjectiveTNTSpawner +{ + private static final long TNT_SPAWN_DELAY = 60000; + private List _locs; + private Location _lastSpawnLoc; + private Item _entity; + private long _lastPickedUp; + + public ObjectiveTNTSpawner(List locs) + { + _locs = locs; + _lastSpawnLoc = null; + _entity = null; + _lastPickedUp = System.currentTimeMillis(); + } + + public Item getItem() + { + return _entity; + } + + public boolean isSpawned() + { + return _entity != null; + } + + public boolean canPlaceFireAt(Block block) + { + for (Location loc : _locs) + { + if (UtilMath.offsetSquared(loc, block.getLocation()) <= 9) + { + return false; + } + } + + return true; + } + + public long getNextTNT() + { + return (_lastPickedUp + TNT_SPAWN_DELAY) - System.currentTimeMillis(); + } + + public void spawn() + { + Location spawn = _locs.get(UtilMath.r(_locs.size())); + spawn.getBlock().getRelative(BlockFace.DOWN).setType(Material.REDSTONE_BLOCK); + _lastSpawnLoc = spawn.clone(); + _entity = spawn.getWorld().dropItem(spawn, new ItemStack(Material.TNT)); + UtilFirework.playFirework(spawn, Type.BURST, Color.RED, false, false); + } + + public void pickup() + { + _entity.getLocation().getBlock().getRelative(BlockFace.DOWN).setType(Material.IRON_BLOCK); + _entity.remove(); + _entity = null; + _lastSpawnLoc = null; + _lastPickedUp = System.currentTimeMillis(); + } + + public void update() + { + if (!isSpawned() && UtilTime.elapsed(_lastPickedUp, TNT_SPAWN_DELAY)) + { + spawn(); + } + else if (isSpawned()) + { + _entity.teleport(_lastSpawnLoc); + if (!_entity.isValid() || _entity.isDead()) + { + _entity = _lastSpawnLoc.getWorld().dropItem(_lastSpawnLoc, new ItemStack(Material.TNT)); + } + } + } + + public void onStart() + { + _lastPickedUp = System.currentTimeMillis(); + } } \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamCrystal.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamCrystal.java index e44bc9e9a..243389adb 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamCrystal.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamCrystal.java @@ -1,54 +1,54 @@ -package nautilus.game.arcade.game.games.castleassault.data; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.EnderCrystal; - -import nautilus.game.arcade.game.GameTeam; - -public class TeamCrystal -{ - private Location _loc; - private GameTeam _owner; - private EnderCrystal _crystal; - private boolean _destroyed; - - public TeamCrystal(GameTeam owner, Location loc) - { - _owner = owner; - _loc = loc; - - spawn(); - } - - public GameTeam getOwner() - { - return _owner; - } - - public Location getLocation() - { - return _loc; - } - - public boolean isActive() - { - return !_destroyed; - } - - public void spawn() - { - _destroyed = false; - _crystal = _loc.getWorld().spawn(_loc, EnderCrystal.class); - _loc.getBlock().getRelative(0, -2, 0).setType(Material.BEACON); - } - - public void destroy() - { - _destroyed = true; - _crystal.remove(); - _crystal = null; - _loc.getBlock().getRelative(0, -2, 0).setType(Material.SMOOTH_BRICK); - } +package nautilus.game.arcade.game.games.castleassault.data; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.EnderCrystal; + +import nautilus.game.arcade.game.GameTeam; + +public class TeamCrystal +{ + private Location _loc; + private GameTeam _owner; + private EnderCrystal _crystal; + private boolean _destroyed; + + public TeamCrystal(GameTeam owner, Location loc) + { + _owner = owner; + _loc = loc; + + spawn(); + } + + public GameTeam getOwner() + { + return _owner; + } + + public Location getLocation() + { + return _loc; + } + + public boolean isActive() + { + return !_destroyed; + } + + public void spawn() + { + _destroyed = false; + _crystal = _loc.getWorld().spawn(_loc, EnderCrystal.class); + _loc.getBlock().getRelative(0, -2, 0).setType(Material.BEACON); + } + + public void destroy() + { + _destroyed = true; + _crystal.remove(); + _crystal = null; + _loc.getBlock().getRelative(0, -2, 0).setType(Material.SMOOTH_BRICK); + } } \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamKing.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamKing.java index c12c1dd5b..5399b38ae 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamKing.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/castleassault/data/TeamKing.java @@ -125,4 +125,4 @@ public class TeamKing return true; } -} +} \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsCTF.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsCTF.java index d419b8c3f..1a28d319c 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsCTF.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsCTF.java @@ -14,6 +14,7 @@ import nautilus.game.arcade.game.games.champions.kits.KitBrute; import nautilus.game.arcade.game.games.champions.kits.KitKnight; import nautilus.game.arcade.game.games.champions.kits.KitMage; import nautilus.game.arcade.game.games.champions.kits.KitRanger; +import nautilus.game.arcade.game.games.champions.quests.FlagQuestTracker; import nautilus.game.arcade.game.games.common.CaptureTheFlag; import nautilus.game.arcade.kit.Kit; import nautilus.game.arcade.managers.chat.ChatStatData; @@ -83,6 +84,8 @@ public class ChampionsCTF extends CaptureTheFlag new ClutchStatTracker(this, "Clutch"), new SpecialWinStatTracker(this, "SpecialWin") ); + + registerQuestTrackers(new FlagQuestTracker(this)); registerChatStats( Kills, diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsDominate.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsDominate.java index 226a3e364..bc59c9d56 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsDominate.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/ChampionsDominate.java @@ -14,6 +14,7 @@ import nautilus.game.arcade.game.games.champions.kits.KitBrute; import nautilus.game.arcade.game.games.champions.kits.KitKnight; import nautilus.game.arcade.game.games.champions.kits.KitMage; import nautilus.game.arcade.game.games.champions.kits.KitRanger; +import nautilus.game.arcade.game.games.champions.quests.CaptureQuestTracker; import nautilus.game.arcade.game.games.common.Domination; import nautilus.game.arcade.kit.Kit; import nautilus.game.arcade.stats.ElectrocutionStatTracker; @@ -77,6 +78,8 @@ public class ChampionsDominate extends Domination new TheLongestShotStatTracker(this), new SeismicSlamStatTracker(this) ); + + registerQuestTrackers(new CaptureQuestTracker(this)); registerChatStats( Kills, diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/events/CaptureEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/events/CaptureEvent.java new file mode 100644 index 000000000..1bdd04cb3 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/events/CaptureEvent.java @@ -0,0 +1,41 @@ +package nautilus.game.arcade.game.games.champions.events; + +import java.util.Collection; + +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * CaptureEvent + * + * @author xXVevzZXx + */ +public class CaptureEvent extends Event +{ + private Collection _players; + + public CaptureEvent(Collection players) + { + _players = players; + } + + public Collection getPlayers() + { + return _players; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + + private static HandlerList _handlers = new HandlerList(); + + public static HandlerList getHandlerList() + { + return _handlers; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/CaptureQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/CaptureQuestTracker.java new file mode 100644 index 000000000..9a2f065c5 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/CaptureQuestTracker.java @@ -0,0 +1,32 @@ +package nautilus.game.arcade.game.games.champions.quests; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.games.champions.ChampionsDominate; +import nautilus.game.arcade.game.games.champions.events.CaptureEvent; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * PointQuestTracker + * + * @author xXVevzZXx + */ +public class CaptureQuestTracker extends QuestTracker +{ + + public CaptureQuestTracker(ChampionsDominate game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler + public void capture(CaptureEvent event) + { + for (Player player : event.getPlayers()) + incrementQuests(player, 1, "Point Capture"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/FlagQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/FlagQuestTracker.java new file mode 100644 index 000000000..92b9be1c2 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/champions/quests/FlagQuestTracker.java @@ -0,0 +1,30 @@ +package nautilus.game.arcade.game.games.champions.quests; + +import org.bukkit.event.EventHandler; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.games.common.CaptureTheFlag; +import nautilus.game.arcade.game.games.common.ctf_data.PlayerCaptureFlagEvent; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * FlagQuestTracker + * + * @author xXVevzZXx + */ +public class FlagQuestTracker extends QuestTracker +{ + + public FlagQuestTracker(CaptureTheFlag game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler + public void captureFlag(PlayerCaptureFlagEvent event) + { + incrementQuests(event.GetPlayer(), 1, "Flag Capture"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/common/dominate_data/CapturePoint.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/common/dominate_data/CapturePoint.java index 6dd87d7f5..2a2c11ecd 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/common/dominate_data/CapturePoint.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/common/dominate_data/CapturePoint.java @@ -7,9 +7,11 @@ import mineplex.core.common.util.C; import mineplex.core.common.util.UtilFirework; import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTime; import mineplex.core.common.util.UtilTextMiddle; import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.champions.events.CaptureEvent; import nautilus.game.arcade.game.games.common.Domination; import org.bukkit.ChatColor; @@ -303,6 +305,8 @@ public class CapturePoint } UtilTextMiddle.display(null, _owner.GetColor() + _owner.GetName() + " captured " + _name, 5, 40, 5); + + UtilServer.CallEvent(new CaptureEvent(capturers)); } } //Count Down diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/Draw.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/Draw.java index b2f2ba4e7..43e8de9d6 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/Draw.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/Draw.java @@ -52,6 +52,7 @@ import nautilus.game.arcade.game.GameTeam; import nautilus.game.arcade.game.SoloGame; import nautilus.game.arcade.game.games.GameScore; import nautilus.game.arcade.game.games.draw.kits.KitArtist; +import nautilus.game.arcade.game.games.draw.quests.GuessQuestTracker; import nautilus.game.arcade.game.games.draw.tools.Tool; import nautilus.game.arcade.game.games.draw.tools.ToolCircle; import nautilus.game.arcade.game.games.draw.tools.ToolLine; @@ -254,6 +255,8 @@ public class Draw extends SoloGame new DrawGuessStatTracker(this) ); + registerQuestTrackers(new GuessQuestTracker(this)); + registerChatStats( new ChatStatData("TotalGuess", "Total Guesses", true), new ChatStatData("PureLuck", "Lucky Guesses", true) diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/quests/GuessQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/quests/GuessQuestTracker.java new file mode 100644 index 000000000..786510591 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/draw/quests/GuessQuestTracker.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.draw.quests; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.games.draw.Draw; +import nautilus.game.arcade.game.games.draw.DrawGuessCorrectlyEvent; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * GuesQuestTracker + * + * @author xXVevzZXx + */ +public class GuessQuestTracker extends QuestTracker +{ + + public GuessQuestTracker(Draw game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onDrawGuessCorrectly(DrawGuessCorrectlyEvent event) + { + if (getGame().GetState() != GameState.Live) + return; + + if (System.currentTimeMillis() - event.getDrawRound().Time < 8000) + incrementQuests(event.getPlayer(), 1, "Guesses"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitEnderman.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitEnderman.java index 60fb991dd..34196d101 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitEnderman.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitEnderman.java @@ -19,7 +19,7 @@ public class KitEnderman // @Override // protected void giveItems(Player player) // { -// player.getInventory().addItem(ItemStackFactory.Instance.CreateStack(Material.IRON_SWORD)); +// player.getInventory().addSkillItem(ItemStackFactory.Instance.CreateStack(Material.IRON_SWORD)); // // player.getWorld().playSound(player.getLocation(), Sound.ENDERMAN_IDLE, 4f, 1f); // diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitSkeleton.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitSkeleton.java index d4831cbbb..ffe96719e 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitSkeleton.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/evolution/mobs/KitSkeleton.java @@ -34,7 +34,7 @@ public class KitSkeleton // player.getInventory().setLeggings(new ItemBuilder(Material.CHAINMAIL_LEGGINGS).build()); // player.getInventory().setBoots(new ItemBuilder(Material.IRON_BOOTS).build()); // -// player.getInventory().addItem(ItemStackFactory.Instance.CreateStack(Material.BOW)); +// player.getInventory().addSkillItem(ItemStackFactory.Instance.CreateStack(Material.BOW)); // // player.getWorld().playSound(player.getLocation(), Sound.SKELETON_IDLE, 4f, 1f); // diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/gravity/kits/KitJetpack.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/gravity/kits/KitJetpack.java index f1797298f..ab3ffbf3b 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/gravity/kits/KitJetpack.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/gravity/kits/KitJetpack.java @@ -42,9 +42,9 @@ public class KitJetpack extends ProgressingKit @Override public void GiveItems(Player player) { - //player.getInventory().addItem(ItemStackFactory.Instance.CreateStack(Material.SHEARS, (byte)0, 1, "Block Cannon")); - //player.getInventory().addItem(ItemStackFactory.Instance.CreateStack(Material.BOW, (byte)0, 1, "Space Shooter")); - //player.getInventory().addItem(ItemStackFactory.Instance.CreateStack(Material.ARROW, (byte)0, 64, "Space Arrows")); + //player.getInventory().addSkillItem(ItemStackFactory.Instance.CreateStack(Material.SHEARS, (byte)0, 1, "Block Cannon")); + //player.getInventory().addSkillItem(ItemStackFactory.Instance.CreateStack(Material.BOW, (byte)0, 1, "Space Shooter")); + //player.getInventory().addSkillItem(ItemStackFactory.Instance.CreateStack(Material.ARROW, (byte)0, 64, "Space Arrows")); player.getInventory().addItem(PLAYER_ITEMS); player.getInventory().setArmorContents(PLAYER_ARMOR); } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/HideSeek.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/HideSeek.java index ea2c1d71c..eaedf92cf 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/HideSeek.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/HideSeek.java @@ -46,6 +46,7 @@ import nautilus.game.arcade.game.games.hideseek.kits.KitHiderSwapper; import nautilus.game.arcade.game.games.hideseek.kits.KitSeekerLeaper; import nautilus.game.arcade.game.games.hideseek.kits.KitSeekerRadar; import nautilus.game.arcade.game.games.hideseek.kits.KitSeekerTNT; +import nautilus.game.arcade.game.games.hideseek.quests.DisguiseQuestTracker; import nautilus.game.arcade.game.modules.compass.CompassModule; import nautilus.game.arcade.kit.Kit; import nautilus.game.arcade.kit.NullKit; @@ -348,6 +349,8 @@ public class HideSeek extends TeamGame new HunterOfTheYearStatTracker(this), new BadHiderStatTracker(this) ); + + registerQuestTrackers(new DisguiseQuestTracker(this)); //Need ideas for this one registerChatStats(); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/quests/DisguiseQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/quests/DisguiseQuestTracker.java new file mode 100644 index 000000000..494b72154 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/hideseek/quests/DisguiseQuestTracker.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.hideseek.quests; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.games.hideseek.HideSeek; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * DisguiseQuestTracker + * + * @author xXVevzZXx + */ +public class DisguiseQuestTracker extends QuestTracker +{ + + public DisguiseQuestTracker(HideSeek game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onChangeForm(HideSeek.PlayerChangeFormEvent event) + { + if (getGame().GetState() != Game.GameState.Live) + return; + + incrementQuests(event.getPlayer(), 1, "Disguise"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minecraftleague/MinecraftLeague.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minecraftleague/MinecraftLeague.java index 1590dc86f..d0d92f862 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minecraftleague/MinecraftLeague.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/minecraftleague/MinecraftLeague.java @@ -1470,7 +1470,7 @@ public class MinecraftLeague extends RankedTeamGame player.getInventory().setBoots(new ItemBuilder(Material.LEATHER_BOOTS).setColor(Color.BLUE).setUnbreakable(true).build()); player.getInventory().addItem(new ItemStack(Material.STONE_SWORD)); player.getInventory().addItem(new ItemStack(Material.STONE_PICKAXE)); - //player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 5)); + //player.getInventory().addSkillItem(new ItemStack(Material.COOKED_BEEF, 5)); _blockLock.put(player, new BlockProtection(this, player)); _noFall.add(player); } @@ -1482,7 +1482,7 @@ public class MinecraftLeague extends RankedTeamGame player.getInventory().setBoots(new ItemBuilder(Material.LEATHER_BOOTS).setColor(Color.RED).setUnbreakable(true).build()); player.getInventory().addItem(new ItemStack(Material.STONE_SWORD)); player.getInventory().addItem(new ItemStack(Material.STONE_PICKAXE)); - //player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 5)); + //player.getInventory().addSkillItem(new ItemStack(Material.COOKED_BEEF, 5)); _blockLock.put(player, new BlockProtection(this, player)); _noFall.add(player); } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/Moba.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/Moba.java index 17f393dd6..3850dcc77 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/Moba.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/Moba.java @@ -1,50 +1,780 @@ package nautilus.game.arcade.game.games.moba; -import java.util.ArrayList; - +import mineplex.core.Managers; +import mineplex.core.beta.BetaWhitelist; +import mineplex.core.common.Pair; +import mineplex.core.common.Rank; +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.UtilTime; +import mineplex.core.disguise.disguises.DisguiseBase; +import mineplex.core.disguise.disguises.DisguisePlayer; +import mineplex.core.leaderboard.Leaderboard; +import mineplex.core.leaderboard.LeaderboardManager; +import mineplex.core.leaderboard.LeaderboardRepository.LeaderboardSQLType; +import mineplex.minecraft.game.core.combat.DeathMessageType; import nautilus.game.arcade.ArcadeManager; import nautilus.game.arcade.GameType; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.events.PlayerPrepareTeleportEvent; +import nautilus.game.arcade.game.DebugCommand; +import nautilus.game.arcade.game.GameTeam; import nautilus.game.arcade.game.TeamGame; -import nautilus.game.arcade.game.games.sheep.kits.*; +import nautilus.game.arcade.game.games.moba.boss.BossManager; +import nautilus.game.arcade.game.games.moba.boss.wither.WitherBoss; +import nautilus.game.arcade.game.games.moba.buff.BuffManager; +import nautilus.game.arcade.game.games.moba.fountain.MobaFountain; +import nautilus.game.arcade.game.games.moba.general.ArrowKBManager; +import nautilus.game.arcade.game.games.moba.general.BetaManager; +import nautilus.game.arcade.game.games.moba.general.EnderPearlManager; +import nautilus.game.arcade.game.games.moba.general.MobaDamageManager; +import nautilus.game.arcade.game.games.moba.gold.GoldManager; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.KitPlayer; +import nautilus.game.arcade.game.games.moba.kit.anath.HeroAnath; +import nautilus.game.arcade.game.games.moba.kit.bardolf.HeroBardolf; +import nautilus.game.arcade.game.games.moba.kit.biff.HeroBiff; +import nautilus.game.arcade.game.games.moba.kit.bob.HeroBob; +import nautilus.game.arcade.game.games.moba.kit.dana.HeroDana; +import nautilus.game.arcade.game.games.moba.kit.devon.HeroDevon; +import nautilus.game.arcade.game.games.moba.kit.hattori.HeroHattori; +import nautilus.game.arcade.game.games.moba.kit.hp.HPManager; +import nautilus.game.arcade.game.games.moba.kit.larissa.HeroLarissa; +import nautilus.game.arcade.game.games.moba.kit.rowena.HeroRowena; +import nautilus.game.arcade.game.games.moba.minion.MinionManager; +import nautilus.game.arcade.game.games.moba.prepare.PrepareManager; +import nautilus.game.arcade.game.games.moba.prepare.PrepareSelection; +import nautilus.game.arcade.game.games.moba.recall.Recall; +import nautilus.game.arcade.game.games.moba.shop.MobaShop; +import nautilus.game.arcade.game.games.moba.structure.point.CapturePointManager; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerManager; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import nautilus.game.arcade.game.modules.CustomScoreboardModule; import nautilus.game.arcade.game.modules.compass.CompassModule; import nautilus.game.arcade.kit.Kit; -import nautilus.game.arcade.kit.NullKit; +import nautilus.game.arcade.managers.lobby.current.NewGameLobbyManager; +import nautilus.game.arcade.scoreboard.GameScoreboard; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.ArrayList; +import java.util.Arrays; +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; public class Moba extends TeamGame { - private ArrayList _lastScoreboard = new ArrayList(); - public Moba(ArcadeManager manager) + private static final String[] DESCRIPTION = { + "..." + }; + private static final long PREPARE_TIME = TimeUnit.MINUTES.toMillis(1); + + private final HeroKit[] _kits; + + private final Set _playerData = new HashSet<>(); + + private final Set _listeners = new HashSet<>(); + + private final MobaShop _shop; + private final GoldManager _goldManager; + private final BossManager _boss; + private final TowerManager _tower; + private final CapturePointManager _capturePoint; + private final ArrowKBManager _arrowKb; + private final BuffManager _buffs; + private BetaWhitelist _betaWhitelist; + + public Moba(ArcadeManager manager) { - super(manager, GameType.Sheep, + super(manager, GameType.MOBA, new Kit[]{new KitPlayer(manager)}, DESCRIPTION); - new Kit[] - { - new NullKit(manager) - }, + _kits = new HeroKit[]{ + new HeroHattori(Manager), + new HeroDevon(Manager), + new HeroAnath(Manager), + new HeroDana(Manager), + new HeroBiff(Manager), + new HeroLarissa(Manager), + new HeroBardolf(Manager), + new HeroRowena(Manager), + new HeroBob(Manager) + }; - new String[] - { - "..." - }); + AllowParticles = false; + DontAllowOverfill = true; + PrepareAutoAnnounce = false; + PrepareFreeze = false; + PrepareTime = PREPARE_TIME; + DeathOut = false; + DeathSpectateSecs = 12; + HungerSet = 20; + DamageFall = false; - this.DeathOut = false; - this.DeathSpectateSecs = 8; - - this.HungerSet = 20; + manager.getCosmeticManager().setHideParticles(true); + manager.GetCreature().SetDisableCustomDrops(true); - registerChatStats(); + // Instantiate managers + + // Global managers + _shop = registerManager(new MobaShop(this)); + _goldManager = registerManager(new GoldManager(this)); + registerManager(new HPManager(this)); + registerManager(new MobaDamageManager(this)); + registerManager(new MobaFountain(this)); + registerManager(new Recall(this)); + + // Pregame managers + registerManager(new PrepareManager(this)); + registerManager(new PrepareSelection(this)); + + // Bosses + _boss = registerManager(new BossManager(this)); + + // Structures + _tower = registerManager(new TowerManager(this)); + _capturePoint = registerManager(new CapturePointManager(this)); + + // Minions + registerManager(new MinionManager(this)); + + // Arrow Knockback + _arrowKb = registerManager(new ArrowKBManager(this)); + + // Ender Pearls + registerManager(new EnderPearlManager()); + + // Buffs + _buffs = registerManager(new BuffManager()); + + // Beta Message + registerManager(new BetaManager(this)); + + // Beta Whitelist + _betaWhitelist = Managers.get(BetaWhitelist.class); + if (_betaWhitelist == null) + { + _betaWhitelist = new BetaWhitelist(manager.GetClients(), manager.getBonusManager().getPowerPlayClubRepository()); + } + else + { + _betaWhitelist.registerSelf(); + } new CompassModule() .setGiveCompass(true) .setGiveCompassToSpecs(true) .setGiveCompassToAlive(false) .register(this); + + new CustomScoreboardModule() + .setSidebar((player, scoreboard) -> + { + GameState state = GetState(); + + switch (state) + { + case Prepare: + writePrepare(player, scoreboard); + break; + case Live: + writeLive(player, scoreboard); + break; + } + }) + .setPrefix((perspective, subject) -> + { + if (!IsAlive(subject)) + { + return C.cGray; + } + + GameTeam team = GetTeam(subject); + + return team.GetColor().toString(); + }) + .setSuffix((perspective, subject) -> + { + GameState state = GetState(); + GameTeam perspectiveTeam = GetTeam(perspective); + GameTeam subjectTeam = GetTeam(subject); + + if (!IsAlive(subject) || perspectiveTeam == null || subjectTeam == null) + { + return ""; + } + + MobaPlayer mobaPlayer = getMobaData(subject); + String suffix; + + if (state == GameState.Prepare && !perspectiveTeam.equals(subjectTeam)) + { + suffix = C.cYellow + " Unknown"; + } + else if (mobaPlayer.getKit() == null) + { + suffix = C.cYellow + " Selecting"; + } + else + { + suffix = mobaPlayer.getRole().getChatColor() + " " + mobaPlayer.getKit().GetName(); + } + + return suffix + C.Reset; + }) + .setUnderNameObjective(C.cRed + "❤") + .setUnderName((perspective, subject) -> + (int) (Math.ceil(subject.getHealth() / 2D))) + .register(this); + + registerDebugCommand(new DebugCommand("kit", Rank.ADMIN) + { + @Override + public void Execute(Player caller, String[] args) + { + StringBuilder builder = new StringBuilder(); + + for (String arg : args) + { + builder.append(arg).append(" "); + } + + String kit = builder.toString().trim(); + + for (Kit kits : _kits) + { + if (kit.equalsIgnoreCase(kits.GetName())) + { + SetKit(caller, kits, true); + return; + } + } + + caller.sendMessage(F.main("Kit", "Sorry that is not a kit!")); + } + }); + } + + private T registerManager(T listener) + { + _listeners.add(listener); + return listener; } @Override - public void ParseData() + public void ParseData() { - + // Register all "Managers" + _listeners.forEach(UtilServer::RegisterEvents); + + // Make all spawns face the center of the map + for (List locations : WorldData.SpawnLocs.values()) + { + locations.forEach(location -> location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, GetSpectatorLocation())))); + } + + SpectatorSpawn = WorldData.GetCustomLocs("CENTER").get(0); + + // Leaderboards + if (Manager.IsRewardStats()) + { + if (Manager.GetLobby() instanceof NewGameLobbyManager) + { + Map> lobbyCustomLocs = ((NewGameLobbyManager) Manager.GetLobby()).getCustomLocs(); + LeaderboardManager leaderboard = Managers.get(LeaderboardManager.class); + Pair winPair = Pair.create("Win", "Wins"); + Pair killPair = Pair.create("Kill", "Kills"); + Pair goldPair = Pair.create("Gold", "Gold"); + + { + Location location = lobbyCustomLocs.get("TOP_DAILY_WINS").get(0); + leaderboard.registerLeaderboard("TOP_HOG_DAILY_WINS", new Leaderboard("Top Daily Wins", winPair, new String[]{GetName() + ".Wins"}, LeaderboardSQLType.DAILY, location, 10)); + } + { + Location location = lobbyCustomLocs.get("TOP_DAILY_KILLS").get(0); + leaderboard.registerLeaderboard("TOP_HOG_DAILY_KILLS", new Leaderboard("Top Daily Kills", killPair, new String[]{GetName() + ".Kills"}, LeaderboardSQLType.DAILY, location, 10)); + } + { + Location location = lobbyCustomLocs.get("TOP_DAILY_GOLD").get(0); + leaderboard.registerLeaderboard("TOP_HOG_DAILY_GOLD", new Leaderboard("Top Daily Gold Earned", goldPair, new String[]{GetName() + ".GoldEarned"}, LeaderboardSQLType.DAILY, location, 10)); + } + { + Location location = lobbyCustomLocs.get("TOP_WINS").get(0); + leaderboard.registerLeaderboard("TOP_HOG_WINS", new Leaderboard("Top Wins", winPair, new String[]{GetName() + ".Wins"}, LeaderboardSQLType.ALL, location, 10)); + } + { + Location location = lobbyCustomLocs.get("TOP_KILLS").get(0); + leaderboard.registerLeaderboard("TOP_HOG_KILLS", new Leaderboard("Top Kills", killPair, new String[]{GetName() + ".Kills"}, LeaderboardSQLType.ALL, location, 10)); + } + { + Location location = lobbyCustomLocs.get("TOP_GOLD").get(0); + leaderboard.registerLeaderboard("TOP_HOG_GOLD", new Leaderboard("Top Gold Earned", goldPair, new String[]{GetName() + ".GoldEarned"}, LeaderboardSQLType.ALL, location, 10)); + } + } + } + } + + private void writePrepare(Player player, GameScoreboard scoreboard) + { + MobaPlayer mobaPlayer = getMobaData(player); + + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Hero Selection"); + scoreboard.write(UtilTime.MakeStr(GetStateTime() + PREPARE_TIME - System.currentTimeMillis())); + + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Hero"); + scoreboard.write((mobaPlayer == null || mobaPlayer.getKit() == null) ? "Unselected " : mobaPlayer.getKit().GetName() + " (" + mobaPlayer.getRole().getName() + ")"); + + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Players"); + int kits = 0; + + for (MobaPlayer otherMobaPlayer : _playerData) + { + if (otherMobaPlayer.getKit() != null) + { + kits++; + } + } + + scoreboard.write(kits + "/" + GetPlayers(true).size()); + + scoreboard.writeNewLine(); + } + + private void writeLive(Player player, GameScoreboard scoreboard) + { + GameTeam team = GetTeam(player); + boolean alive = IsAlive(player); + + scoreboard.writeNewLine(); + + // Towers + GameTeam red = GetTeam(ChatColor.RED); + GameTeam blue = GetTeam(ChatColor.AQUA); + String redTitle; + String blueTitle; + + if (alive) + { + boolean playerRed = team.equals(red); + redTitle = playerRed ? "Your Team" : "Enemy Team"; + blueTitle = playerRed ? "Enemy Team" : "Your Team"; + } + else + { + redTitle = "Red Team"; + blueTitle = "Blue Team"; + } + + scoreboard.write(red.GetColor() + C.Bold + redTitle); + scoreboard.write("Base: " + _tower.getDisplayString(red) + _boss.getWitherDisplayString(red)); + + scoreboard.writeNewLine(); + + scoreboard.write(blue.GetColor() + C.Bold + blueTitle); + scoreboard.write("Base: " + _tower.getDisplayString(blue) + _boss.getWitherDisplayString(blue)); + + scoreboard.writeNewLine(); + + scoreboard.write(C.cGreenB + "Beacons"); + scoreboard.write(_capturePoint.getDisplayString()); + + scoreboard.writeNewLine(); + + // Gold + scoreboard.write(C.cGoldB + "Your Gold"); + if (alive) + { + int gold = _goldManager.getGold(player); + + scoreboard.write(String.valueOf(gold)); + } + else + { + scoreboard.write("None"); + } + + scoreboard.writeNewLine(); + + scoreboard.write(C.cYellowB + "Time"); + scoreboard.write(UtilTime.MakeStr(System.currentTimeMillis() - GetStateTime())); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + // Override those kits! + setKits(_kits); + + // Store player data + for (Player player : GetPlayers(true)) + { + _playerData.add(new MobaPlayer(player)); + MobaUtil.setTeamEntity(player, GetTeam(player)); + } + } + + @EventHandler + public void preventOverfill(PlayerPrepareTeleportEvent event) + { + Player player = event.GetPlayer(); + + if (GetPlayers(true).size() > 8) + { + SetPlayerState(player, GameTeam.PlayerState.OUT); + Manager.addSpectator(player, true); + player.sendMessage(F.main("Game", "Too many players are in this server. You are now spectating, sorry.")); + } + } + + @Override + public void EndCheck() + { + if (!IsLive()) + { + return; + } + + // Only one team online check + List teamsWithPlayers = new ArrayList<>(GetTeamList().size()); + + for (GameTeam team : GetTeamList()) + { + if (team.GetPlayers(true).isEmpty()) + { + continue; + } + + teamsWithPlayers.add(team); + } + + if (teamsWithPlayers.size() == 1) + { + AnnounceEnd(teamsWithPlayers.get(0)); + SetState(GameState.End); + return; + } + + // Wither Dead check + for (GameTeam team : GetTeamList()) + { + WitherBoss boss = _boss.getWitherBoss(team); + LivingEntity entity = boss.getEntity(); + + // Dead Wither + if (entity == null || !entity.isValid() || entity.isDead()) + { + // Get the other team + for (GameTeam otherTeam : GetTeamList()) + { + for (Player player : otherTeam.GetPlayers(true)) + { + AddGems(player, 10, "Participation", false, false); + } + + if (team.equals(otherTeam)) + { + continue; + } + + for (Player player : otherTeam.GetPlayers(true)) + { + AddGems(player, 20, "Winning", false, false); + } + + AnnounceEnd(otherTeam); + SetState(GameState.End); + } + } + } + } + + @Override + public void RespawnPlayer(Player player) + { + super.RespawnPlayer(player); + player.setGameMode(GameMode.ADVENTURE); + } + + @Override + public void disable() + { + super.disable(); + _listeners.forEach(UtilServer::Unregister); + _listeners.clear(); + _betaWhitelist.deregisterSelf(); + } + + @Override + public void SetKit(Player player, Kit kit, boolean announce) + { + super.SetKit(player, kit, announce); + + if (kit instanceof HeroKit) + { + getMobaData(player).setKit((HeroKit) kit); + } + } + + @Override + public DeathMessageType GetDeathMessageType() + { + return DeathMessageType.Detailed; + } + + // Clear up memory + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + + _playerData.removeIf(mobaPlayer -> mobaPlayer.getPlayer().equals(player)); + } + + // Clean up arrows + @EventHandler + public void projectileHit(ProjectileHitEvent event) + { + if (event.getEntity() instanceof Arrow) + { + event.getEntity().remove(); + } + } + + // Undisguise everyone upon game end + @EventHandler + public void end(GameStateChangeEvent event) + { + if (event.GetState() != GameState.End && event.GetState() != GameState.Dead) + { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + DisguiseBase disguise = Manager.GetDisguise().getActiveDisguise(player); + + if (disguise != null && disguise instanceof DisguisePlayer) + { + Manager.GetDisguise().undisguise(disguise); + } + } + } + + public Map getLocationStartsWith(String s) + { + Map map = new HashMap<>(); + + for (String key : WorldData.GetAllCustomLocs().keySet()) + { + if (key.startsWith(s)) + { + map.put(key, WorldData.GetCustomLocs(key).get(0)); + } + } + + return map; + } + + public GameTeam getTeam(String name) + { + for (GameTeam team : GetTeamList()) + { + if (team.GetName().equalsIgnoreCase(name)) + { + return team; + } + } + + return null; + } + + public HeroKit[] getKits() + { + return _kits; + } + + public List getKits(MobaRole role) + { + List kits = new ArrayList<>(); + + for (HeroKit kit : _kits) + { + if (kit.getRole() == role && kit.isVisible()) + { + kits.add(kit); + } + } + + return kits; + } + + public Set getMobaData() + { + return _playerData; + } + + public MobaPlayer getMobaData(Player player) + { + for (MobaPlayer mobaPlayer : _playerData) + { + if (mobaPlayer.getPlayer().equals(player)) + { + return mobaPlayer; + } + } + + return null; + } + + public HeroKit getFirstKit(Player player) + { + MobaPlayer mobaPlayer = getMobaData(player); + + if (mobaPlayer.getRole() == null) + { + MobaRole role = getRandomRole(player); + + return getFirstKit(role); + } + else if (mobaPlayer.getKit() == null) + { + return getFirstKit(mobaPlayer.getRole()); + } + + return null; + } + + private HeroKit getFirstKit(MobaRole role) + { + for (HeroKit kit : _kits) + { + if (kit.getRole() == role && kit.isVisible()) + { + return kit; + } + } + + return null; + } + + private MobaRole getRandomRole(Player player) + { + List roles = new ArrayList<>(); + + for (MobaPlayer mobaPlayer : getTeamData(GetTeam(player))) + { + MobaRole role = mobaPlayer.getRole(); + + if (role != null) + { + roles.add(role); + } + } + + return UtilAlg.Random(Arrays.asList(MobaRole.values()), roles); + } + + private List getTeamData(GameTeam team) + { + List players = new ArrayList<>(); + + for (MobaPlayer mobaPlayer : _playerData) + { + GameTeam otherTeam = GetTeam(mobaPlayer.getPlayer()); + + if (team.equals(otherTeam)) + { + players.add(mobaPlayer); + } + } + + return players; + } + + public boolean isRoleFree(Player player, MobaRole role) + { + GameTeam team = GetTeam(player); + + if (team == null) + { + return false; + } + + for (MobaPlayer mobaPlayer : getTeamData(team)) + { + if (mobaPlayer.getRole() == role) + { + return false; + } + } + + return true; + } + + public CustomScoreboardModule getScoreboardModule() + { + return getModule(CustomScoreboardModule.class); + } + + public MobaShop getShop() + { + return _shop; + } + + public GoldManager getGoldManager() + { + return _goldManager; + } + + public TowerManager getTowerManager() + { + return _tower; + } + + public CapturePointManager getCapturePointManager() + { + return _capturePoint; + } + + public BossManager getBossManager() + { + return _boss; + } + + public ArrowKBManager getArrowKbManager() + { + return _arrowKb; + } + + public BuffManager getBuffManager() + { + return _buffs; } } \ No newline at end of file diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaPlayer.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaPlayer.java new file mode 100644 index 000000000..29d7083ed --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaPlayer.java @@ -0,0 +1,42 @@ +package nautilus.game.arcade.game.games.moba; + +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import org.bukkit.entity.Player; + +public class MobaPlayer +{ + + private final Player _player; + private MobaRole _role; + private HeroKit _kit; + + public MobaPlayer(Player player) + { + _player = player; + } + + public Player getPlayer() + { + return _player; + } + + public void setRole(MobaRole role) + { + _role = role; + } + + public MobaRole getRole() + { + return _role; + } + + public void setKit(HeroKit kit) + { + _kit = kit; + } + + public HeroKit getKit() + { + return _kit; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaRole.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaRole.java new file mode 100644 index 000000000..014d12a4d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/MobaRole.java @@ -0,0 +1,40 @@ +package nautilus.game.arcade.game.games.moba; + +import org.bukkit.ChatColor; +import org.bukkit.Color; + +public enum MobaRole +{ + + ASSASSIN("Assassin", Color.GRAY, ChatColor.DARK_GRAY), + HUNTER("Hunter", Color.LIME, ChatColor.GREEN), + MAGE("Mage", Color.PURPLE, ChatColor.DARK_PURPLE), + WARRIOR("Warrior", Color.YELLOW, ChatColor.GOLD), + ; + + private final String _name; + private final Color _color; + private final ChatColor _chatColor; + + MobaRole(String name, Color color, ChatColor chatColor) + { + _name = name; + _color = color; + _chatColor = chatColor; + } + + public String getName() + { + return _name; + } + + public Color getColor() + { + return _color; + } + + public ChatColor getChatColor() + { + return _chatColor; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/MobaAI.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/MobaAI.java new file mode 100644 index 000000000..15f4e9e49 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/MobaAI.java @@ -0,0 +1,92 @@ +package nautilus.game.arcade.game.games.moba.ai; + +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaAIMethod; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +import java.util.List; + +public class MobaAI +{ + + private final GameTeam _owner; + private final float _speedTarget; + private final float _speedHome; + private final List _boundaries; + + private LivingEntity _entity; + private LivingEntity _target; + private Location _home; + + private MobaAIMethod _aiMethod; + + public MobaAI(Moba host, GameTeam owner, LivingEntity entity, Location home, float speedTarget, float speedHome, MobaAIMethod aiMethod) + { + _owner = owner; + _speedTarget = speedTarget; + _speedHome = speedHome; + _entity = entity; + _home = home; + _aiMethod = aiMethod; + _boundaries = host.WorldData.GetDataLocs(getBoundaryKey()); + } + + public void updateTarget() + { + // Entity not spawned + if (_entity == null || _entity.isDead() || !_entity.isValid()) + { + return; + } + + if (_target == null || _target.isDead() || !_target.isValid()) + { + _target = MobaUtil.getBestEntityTarget(_owner, _entity, _home, _boundaries); + + if (_target == null) + { + returnToHome(); + return; + } + } + else if (!MobaUtil.isInBoundary(_owner, _entity, _home, _boundaries, _target)) + { + _target = null; + returnToHome(); + } + + if (_target != null) + { + _aiMethod.updateMovement(_entity, _target.getLocation(), _speedTarget); + } + } + + private void returnToHome() + { + _aiMethod.updateMovement(_entity, _home, _speedHome); + } + + public void setEntity(LivingEntity entity) + { + _entity = entity; + } + + public LivingEntity getTarget() + { + return _target; + } + + public List getBoundaries() + { + return _boundaries; + } + + public String getBoundaryKey() + { + return _owner.GetColor() == ChatColor.RED ? "ORANGE" : "LIGHT_BLUE"; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaAIMethod.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaAIMethod.java new file mode 100644 index 000000000..bba2324af --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaAIMethod.java @@ -0,0 +1,11 @@ +package nautilus.game.arcade.game.games.moba.ai.goal; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +public interface MobaAIMethod +{ + + boolean updateMovement(LivingEntity entity, Location goal, float speed); + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaDirectAIMethod.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaDirectAIMethod.java new file mode 100644 index 000000000..d2ad46e97 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/ai/goal/MobaDirectAIMethod.java @@ -0,0 +1,45 @@ +package nautilus.game.arcade.game.games.moba.ai.goal; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Vector; + +public class MobaDirectAIMethod implements MobaAIMethod +{ + + @Override + public boolean updateMovement(LivingEntity entity, Location goal, float speed) + { + Location entityLocation = entity.getLocation(); + + // Speed is number of ticks to travel 1 block + float magnitude = speed / 20F; + + // Get the direct vector between the entity and the goal + Vector direction = UtilAlg.getTrajectory(entityLocation, goal); + + // From the direction, get the yaw of this direction + float directionYaw = UtilAlg.GetYaw(direction); + entityLocation.setYaw(directionYaw); + + // If reached the goal + if (UtilMath.offsetSquared(entityLocation, goal) < 4) + { + return false; + } + else + { + // Modify the direction's magnitude to be at the same rate as the speed + direction.multiply(magnitude); + + // Add the modified direction to the original entity location + entityLocation.add(direction); + } + + // Move the entity to its new location + entity.teleport(entityLocation); + return true; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/BossManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/BossManager.java new file mode 100644 index 000000000..f2a0ef23c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/BossManager.java @@ -0,0 +1,99 @@ +package nautilus.game.arcade.game.games.moba.boss; + +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.boss.pumpkin.PumpkinBoss; +import nautilus.game.arcade.game.games.moba.boss.wither.WitherBoss; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import nautilus.game.arcade.world.WorldData; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BossManager implements Listener +{ + + private final Moba _host; + + private Map _teamBosses; + private PumpkinBoss _pumpkinBoss; + + public BossManager(Moba host) + { + _host = host; + _teamBosses = new HashMap<>(2); + } + + private void spawnBosses() + { + _host.CreatureAllowOverride = true; + + WorldData worldData = _host.WorldData; + + // Spawn Team Withers + for (GameTeam team : _host.GetTeamList()) + { + WitherBoss boss = new WitherBoss(_host, worldData.GetDataLocs(team.GetName().toUpperCase()).get(0), team); + boss.setup(); + + _teamBosses.put(team, boss); + } + + // Pumpkin King + _pumpkinBoss = new PumpkinBoss(_host, worldData.GetDataLocs("BLACK").get(0)); + _pumpkinBoss.setup(); + + _host.CreatureAllowOverride = false; + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + spawnBosses(); + } + + @EventHandler + public void cleanup(GameStateChangeEvent event) + { + if (event.GetState() != GameState.End && event.GetState() != GameState.Dead) + { + return; + } + + _teamBosses.forEach((team, witherBoss) -> witherBoss.cleanup()); + _pumpkinBoss.cleanup(); + } + + public String getWitherDisplayString(GameTeam team) + { + WitherBoss boss = getWitherBoss(team); + + return MobaUtil.getColour(boss.getHealthPercentage()) + "♚"; + } + + public WitherBoss getWitherBoss(GameTeam team) + { + return _teamBosses.get(team); + } + + public List getBosses() + { + List bosses = new ArrayList<>(); + + bosses.addAll(_teamBosses.values()); + bosses.add(_pumpkinBoss); + + return bosses; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBoss.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBoss.java new file mode 100644 index 000000000..086858719 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBoss.java @@ -0,0 +1,142 @@ +package nautilus.game.arcade.game.games.moba.boss; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.MobaAI; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public abstract class MobaBoss implements Listener +{ + + protected final Moba _host; + protected LivingEntity _entity; + protected Location _location; + private int _respawnTime; + private long _lastDeath; + + private List _attacks; + + public MobaBoss(Moba host, Location location) + { + this(host, location, -1); + } + + public MobaBoss(Moba host, Location location, int respawnTime) + { + _host = host; + _location = location; + _respawnTime = respawnTime; + _lastDeath = -1; + _attacks = new ArrayList<>(3); + } + + public void setup() + { + _entity = spawnEntity(); + UtilServer.RegisterEvents(this); + } + + public void cleanup() + { + UtilServer.Unregister(this); + _attacks.forEach(MobaBossAttack::cleanup); + } + + public void addAttack(MobaBossAttack attack) + { + _attacks.add(attack); + } + + @EventHandler + public void updateAttack(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOW || getAi().getTarget() == null) + { + return; + } + + MobaBossAttack attack = UtilAlg.Random(_attacks); + + if (attack == null) + { + return; + } + + attack.run(); + } + + @EventHandler + public void updateMovement(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || _entity == null || !_host.IsLive()) + { + return; + } + + getAi().updateTarget(); + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + if (_entity != null && _entity.equals(event.getEntity())) + { + event.getDrops().clear(); + event.setDroppedExp(0); + _entity = null; + _lastDeath = System.currentTimeMillis(); + getAi().setEntity(null); + } + } + + @EventHandler + public void updateRespawn(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || _lastDeath == -1 || !UtilTime.elapsed(_lastDeath, _respawnTime)) + { + return; + } + + _lastDeath = -1; + _entity = spawnEntity(); + getAi().setEntity(_entity); + } + + public abstract LivingEntity spawnEntity(); + + public abstract MobaAI getAi(); + + public abstract String getName(); + + public Moba getHost() + { + return _host; + } + + public LivingEntity getEntity() + { + return _entity; + } + + public boolean isDead() + { + return _entity == null || _entity.isDead() || !_entity.isValid(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBossAttack.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBossAttack.java new file mode 100644 index 000000000..4c91d9f6c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/MobaBossAttack.java @@ -0,0 +1,10 @@ +package nautilus.game.arcade.game.games.moba.boss; + +import org.bukkit.event.Listener; + +public interface MobaBossAttack extends Runnable, Listener +{ + + void cleanup(); + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBoss.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBoss.java new file mode 100644 index 000000000..133a8277e --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBoss.java @@ -0,0 +1,307 @@ +package nautilus.game.arcade.game.games.moba.boss.pumpkin; + +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.UtilEnt; +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.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.utils.UtilVariant; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.MobaAI; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaAIMethod; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaDirectAIMethod; +import nautilus.game.arcade.game.games.moba.boss.MobaBoss; +import nautilus.game.arcade.game.games.moba.buff.BuffManager; +import nautilus.game.arcade.game.games.moba.buff.buffs.BuffPumpkinKing; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import net.minecraft.server.v1_8_R3.PacketPlayOutAnimation; +import org.bukkit.Bukkit; +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.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class PumpkinBoss extends MobaBoss +{ + + private static final String NAME = "Pumpkin King"; + private static final int SPAWN_TIME = (int) TimeUnit.MINUTES.toMillis(5); + private static final int RESPAWN_TIME = (int) TimeUnit.MINUTES.toMillis(5); + private static final MobaAIMethod AI_METHOD = new MobaDirectAIMethod(); + private static final ItemStack HELMET = new ItemStack(Material.PUMPKIN); + private static final ItemStack IN_HAND = new ItemStack(Material.STONE_SWORD); + private static final String DAMAGE_REASON = "Pumpkin King"; + private static final int DAMAGE_RADIUS = 2; + private static final int DAMAGE_RANGE = 2; + private static final int DAMAGE_DIRECT = 6; + private static final int DAMAGE_DIRECT_RADIUS_SQUARED = 9; + private static final int HEALTH = 100; + private static final int HEALTH_OUT_OF_COMBAT = 2; + private static final Material[] BLOCKS = { + Material.OBSIDIAN, + Material.NETHERRACK, + Material.NETHER_BRICK + }; + + private MobaAI _ai; + private boolean _initialSpawn; + private final Set _changed; + + public PumpkinBoss(Moba host, Location location) + { + super(host, location, RESPAWN_TIME); + + _changed = new HashSet<>(); + } + + @Override + public void setup() + { + // Override this so that the entity isn't spawned as soon as the game starts. + UtilServer.RegisterEvents(this); + } + + @Override + public LivingEntity spawnEntity() + { + _host.CreatureAllowOverride = true; + + Skeleton skeleton = UtilVariant.spawnWitherSkeleton(_location); + + skeleton.setCustomName(C.cDRedB + NAME); + skeleton.setCustomNameVisible(true); + skeleton.getEquipment().setHelmet(HELMET); + skeleton.getEquipment().setItemInHand(IN_HAND); + skeleton.setMaxHealth(HEALTH); + skeleton.setHealth(HEALTH); + + UtilEnt.vegetate(skeleton); + UtilEnt.setFakeHead(skeleton, true); + + skeleton.getWorld().strikeLightningEffect(skeleton.getLocation()); + + // preDamage uses getAi() which would have been called in a game long before spawnEntity has + // This is unique to the pumpkin king, so we must manually update the AI's corresponding entity + getAi().setEntity(skeleton); + + UtilTextMiddle.display(C.cDRedB + "The Pumpkin King", "Has Awoken!", 10, 40, 10); + _host.Announce(F.main("Game", C.cRedB + "The Pumpkin King Has Awoken!"), false); + + for (Player player : Bukkit.getOnlinePlayers()) + { + player.playSound(player.getLocation(), Sound.WITHER_SPAWN, 1, 0.4F); + } + + for (Entry entry : UtilBlock.getInRadius(skeleton.getLocation(), 12).entrySet()) + { + Block block = entry.getKey(); + double setChance = entry.getValue(); + + if (!UtilBlock.solid(block)|| block.getRelative(BlockFace.UP).getType() != Material.AIR || Math.random() > setChance) + { + continue; + } + + _host.getArcadeManager().GetBlockRestore().add(block, BLOCKS[UtilMath.r(BLOCKS.length)].getId(), (byte) 0, Integer.MAX_VALUE); + _changed.add(block); + } + + _host.CreatureAllowOverride = false; + + return skeleton; + } + + @Override + public MobaAI getAi() + { + if (_ai == null) + { + _ai = new PumpkinBossAI(_host, _entity, _location, AI_METHOD); + } + + return _ai; + } + + @Override + public String getName() + { + return NAME; + } + + @EventHandler + public void updateSpawn(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || !_host.IsLive() || _initialSpawn || !UtilTime.elapsed(_host.GetStateTime(), SPAWN_TIME)) + { + return; + } + + _initialSpawn = true; + _entity = spawnEntity(); + } + + @Override + public void cleanup() + { + super.cleanup(); + + for (Block block : _changed) + { + _host.getArcadeManager().GetBlockRestore().restore(block); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void preDamage(CustomDamageEvent event) + { + if (!event.GetDamageeEntity().equals(_entity) || MobaUtil.isInBoundary(null, _entity, _location, getAi().getBoundaries(), event.GetDamagerPlayer(true))) + { + return; + } + + event.SetCancelled("Outside of area"); + } + + @Override + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + if (_entity == null || !event.getEntity().equals(_entity)) + { + return; + } + + Player player = _entity.getKiller(); + + if (player == null) + { + return; + } + + super.entityDeath(event); + + GameTeam team = _host.GetTeam(player); + + if (team == null) + { + return; + } + + _host.Announce(F.main("Game", team.GetFormattedName() + C.mBody + " killed the " + C.cDRedB + DAMAGE_REASON), false); + UtilTextMiddle.display("", team.GetFormattedName() + C.cWhite + " killed the " + C.cDRedB + DAMAGE_REASON, 10, 40, 10); + + for (Block block : _changed) + { + _host.getArcadeManager().GetBlockRestore().restore(block); + } + + event.getEntity().getWorld().playSound(event.getEntity().getLocation(), Sound.EXPLODE, 1, 0.2F); + UtilParticle.PlayParticle(ParticleType.HUGE_EXPLOSION, event.getEntity().getEyeLocation(), 1, 1, 1, 0.1F, 3, ViewDist.LONG); + + // Give the team members the buff + BuffManager buffManager = _host.getBuffManager(); + for (Player teamMember : team.GetPlayers(true)) + { + if (UtilPlayer.isSpectator(teamMember)) + { + continue; + } + + buffManager.apply(new BuffPumpkinKing(_host, teamMember)); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void entityDamage(CustomDamageEvent event) + { + if (!event.GetDamageeEntity().equals(_entity)) + { + return; + } + + updateDisplay(); + + if (event.GetCause() == DamageCause.SUFFOCATION) + { + event.SetCancelled("Pumpkin King Suffocation"); + } + } + + @EventHandler + public void updateDamage(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST || _entity == null) + { + return; + } + + LivingEntity target = _ai.getTarget(); + + if (target != null) + { + if (UtilMath.offsetSquared(_entity, target) < DAMAGE_DIRECT_RADIUS_SQUARED) + { + _host.getArcadeManager().GetDamage().NewDamageEvent(target, _entity, null, DamageCause.CUSTOM, DAMAGE_DIRECT, true, true, false, DAMAGE_REASON, DAMAGE_REASON); + + // Send a fake hit packet + // Magic number 0 means swing item/attack + PacketPlayOutAnimation packet = new PacketPlayOutAnimation(((CraftLivingEntity) _entity).getHandle(), 0); + + for (Player player : Bukkit.getOnlinePlayers()) + { + UtilPlayer.sendPacket(player, packet); + } + } + } + else + { + _entity.setHealth(Math.min(_entity.getHealth() + HEALTH_OUT_OF_COMBAT, _entity.getMaxHealth())); + updateDisplay(); + } + + for (LivingEntity entity : UtilEnt.getInRadius(_entity.getLocation(), DAMAGE_RADIUS).keySet()) + { + if (_entity.equals(entity)) + { + continue; + } + + _host.getArcadeManager().GetDamage().NewDamageEvent(entity, _entity, null, DamageCause.CUSTOM, DAMAGE_RANGE, false, true, false, NAME, DAMAGE_REASON); + UtilAction.velocity(entity, UtilAlg.getTrajectory(_entity, entity).setY(1)); + UtilParticle.PlayParticleToAll(ParticleType.FLAME, entity.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5F, 0.1F, 5, ViewDist.LONG); + } + } + + private void updateDisplay() + { + _entity.setCustomName(MobaUtil.getHealthBar(_entity, 20)); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBossAI.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBossAI.java new file mode 100644 index 000000000..6ab78895b --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/pumpkin/PumpkinBossAI.java @@ -0,0 +1,25 @@ +package nautilus.game.arcade.game.games.moba.boss.pumpkin; + +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.MobaAI; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaAIMethod; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; + +public class PumpkinBossAI extends MobaAI +{ + + private static final float SPEED_TARGET = 5F; + private static final float SPEED_HOME = 3F; + + public PumpkinBossAI(Moba host, LivingEntity entity, Location home, MobaAIMethod aiMethod) + { + super(host, null, entity, home, SPEED_TARGET, SPEED_HOME, aiMethod); + } + + @Override + public String getBoundaryKey() + { + return "GRAY"; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/WitherBoss.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/WitherBoss.java new file mode 100644 index 000000000..edf900681 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/WitherBoss.java @@ -0,0 +1,233 @@ +package nautilus.game.arcade.game.games.moba.boss.wither; + +import mineplex.core.common.util.F; +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.common.util.UtilTextTop; +import mineplex.core.common.util.UtilTime; +import mineplex.core.disguise.disguises.DisguiseWither; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.MobaAI; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaAIMethod; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaDirectAIMethod; +import nautilus.game.arcade.game.games.moba.boss.MobaBoss; +import nautilus.game.arcade.game.games.moba.boss.wither.attack.BossAttackEarthquake; +import nautilus.game.arcade.game.games.moba.structure.tower.Tower; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerDestroyEvent; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import java.util.concurrent.TimeUnit; + +public class WitherBoss extends MobaBoss +{ + + private static final String NAME = "Wither Boss"; + private static final float SPEED_TARGET = 4F; + private static final float SPEED_HOME = 6F; + private static final int INITIAL_HEALTH = 125; + private static final MobaAIMethod AI_METHOD = new MobaDirectAIMethod(); + private static final int MIN_INFORM_TIME = (int) TimeUnit.SECONDS.toMillis(30); + + private GameTeam _team; + private MobaAI _ai; + private DisguiseWither _disguise; + private boolean _damageable; + private long _lastInform; + + public WitherBoss(Moba host, Location location, GameTeam team) + { + super(host, location); + + _location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, host.GetSpectatorLocation()))); + _team = team; + + addAttack(new BossAttackEarthquake(this)); + } + + @Override + public LivingEntity spawnEntity() + { + ArmorStand stand = _location.getWorld().spawn(_location, ArmorStand.class); + + // Reducing the wither's health to 10% gives a shield like effect. + stand.setMaxHealth(INITIAL_HEALTH); + stand.setHealth(INITIAL_HEALTH * 0.1); + stand.setGravity(false); + + UtilEnt.setBoundingBox(stand, 3, 5); + + _disguise = new DisguiseWither(stand); + _disguise.setName(_team.GetColor() + _team.GetName() + "\'s Wither"); + _disguise.setCustomNameVisible(true); + _host.getArcadeManager().GetDisguise().disguise(_disguise); + + return stand; + } + + @Override + public MobaAI getAi() + { + if (_ai == null) + { + _ai = new MobaAI(_host, _team, _entity, _location, SPEED_TARGET, SPEED_HOME, AI_METHOD); + } + + return _ai; + } + + @Override + public String getName() + { + return NAME; + } + + @EventHandler(priority = EventPriority.LOWEST) + public void preDamage(CustomDamageEvent event) + { + if (!event.GetDamageeEntity().equals(_entity) || MobaUtil.isInBoundary(_team, _entity, _location, getAi().getBoundaries(), event.GetDamagerPlayer(true))) + { + return; + } + + event.SetCancelled("Outside of area"); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void damage(CustomDamageEvent event) + { + // Not a Wither Boss + if (event.isCancelled() || !(event.GetDamageeEntity().equals(_entity))) + { + return; + } + + event.SetCancelled("Wither Boss"); + + // Fire doesn't damage the wither + if (event.GetCause() == DamageCause.FIRE || event.GetCause() == DamageCause.FIRE_TICK) + { + return; + } + + // If not damageable + if (!_damageable) + { + Player damager = event.GetDamagerPlayer(true); + + if (damager != null) + { + damager.sendMessage(F.main("Game", "You must destroy both towers before attacking the Wither!")); + damager.playSound(damager.getLocation(), Sound.NOTE_BASS, 1, 0.8F); + } + + return; + } + + LivingEntity damagee = event.GetDamageeEntity(); + Player damager = event.GetDamagerPlayer(true); + + if (damager != null) + { + GameTeam team = _host.GetTeam(damager); + + if (team == null || _team.equals(team)) + { + return; + } + } + + // Inform the team + if (UtilTime.elapsed(_lastInform, MIN_INFORM_TIME)) + { + _lastInform = System.currentTimeMillis(); + + for (Player player : _team.GetPlayers(true)) + { + player.playSound(player.getLocation(), Sound.ANVIL_LAND, 1, 0.5F); + player.sendMessage(F.main("Game", "Your Wither is under attack.")); + } + } + + double newHealth = damagee.getHealth() - event.GetDamage(); + + // Don't allow the wither to move because of damage + damagee.playEffect(EntityEffect.HURT); + + if (newHealth > 0) + { + damagee.setHealth(newHealth); + updateDisplay(); + } + else + { + UtilParticle.PlayParticleToAll(ParticleType.HUGE_EXPLOSION, _entity.getLocation().add(0, 1.5, 0), 0F, 0F, 0F, 0.1F, 1, ViewDist.LONG); + _entity.remove(); + } + } + + @EventHandler + public void towerDestroy(TowerDestroyEvent event) + { + Tower tower = event.getTower(); + + if (!_team.equals(tower.getOwner())) + { + return; + } + + // Here we can remove the shield effect, as the wither is no longer invincible + if (!tower.isFirstTower()) + { + _damageable = true; + _entity.setHealth(INITIAL_HEALTH); + updateDisplay(); + } + } + + @EventHandler + public void updateTeamDisplay(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || _entity == null) + { + return; + } + + double percent = getHealthPercentage(); + + for (Player player : _team.GetPlayers(true)) + { + UtilTextTop.displayTextBar(player, percent, _team.GetColor() + "Your Wither"); + } + } + + public double getHealthPercentage() + { + return _damageable ? (_entity.getHealth() / _entity.getMaxHealth()) : 1; + } + + private void updateDisplay() + { + _disguise.setName(MobaUtil.getHealthBar(_entity, 40)); + } + + public GameTeam getTeam() + { + return _team; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/attack/BossAttackEarthquake.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/attack/BossAttackEarthquake.java new file mode 100644 index 000000000..09e6e3cf4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/boss/wither/attack/BossAttackEarthquake.java @@ -0,0 +1,93 @@ +package nautilus.game.arcade.game.games.moba.boss.wither.attack; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilServer; +import nautilus.game.arcade.game.games.moba.boss.MobaBossAttack; +import nautilus.game.arcade.game.games.moba.boss.wither.WitherBoss; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Set; + +public class BossAttackEarthquake implements MobaBossAttack +{ + + private static final String ATTACK_NAME = "Earthquake"; + private static final int RADIUS = 8; + private static final int DAMAGE = 4; + private static final double FALLING_BLOCK_CHANCE = 0.1; + + private final WitherBoss _boss; + private final Set _entities; + + public BossAttackEarthquake(WitherBoss boss) + { + _boss = boss; + _entities = new HashSet<>(); + + UtilServer.RegisterEvents(this); + } + + @Override + public void run() + { + LivingEntity boss = _boss.getEntity(); + + for (Block block : UtilBlock.getBlocksInRadius(boss.getLocation(), RADIUS)) + { + // Only want blocks that are on the floor + if (block.getType() == Material.AIR || block.getRelative(BlockFace.UP).getType() != Material.AIR || Math.random() > FALLING_BLOCK_CHANCE) + { + continue; + } + + FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation().add(0.5, 1, 0.5), block.getType(), block.getData()); + fallingBlock.setHurtEntities(false); + fallingBlock.setDropItem(false); + fallingBlock.setVelocity(UtilAlg.getTrajectory(boss, fallingBlock).multiply(0.25).setY(0.7 + Math.random())); + } + + for (Entry entry : UtilEnt.getInRadius(boss.getLocation(), RADIUS).entrySet()) + { + LivingEntity entity = entry.getKey(); + double dist = entry.getValue(); + + if (MobaUtil.isTeamEntity(entity, _boss.getTeam())) + { + continue; + } + + _boss.getHost().getArcadeManager().GetDamage().NewDamageEvent(entity, boss, null, DamageCause.CUSTOM, DAMAGE * (dist + 0.5), false, true, false, _boss.getName(), ATTACK_NAME); + UtilAction.velocity(entity, UtilAlg.getTrajectory(boss, entity).setY(1)); + } + } + + @Override + public void cleanup() + { + UtilServer.Unregister(this); + } + + @EventHandler + public void entityChangeBlock(EntityChangeBlockEvent event) + { + if (_entities.contains(event.getEntity())) + { + event.setCancelled(true); + event.getEntity().remove(); + _entities.remove(event.getEntity()); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/Buff.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/Buff.java new file mode 100644 index 000000000..5c1d996cc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/Buff.java @@ -0,0 +1,57 @@ +package nautilus.game.arcade.game.games.moba.buff; + +import mineplex.core.common.util.UtilServer; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.Listener; + +public abstract class Buff implements Listener +{ + + protected final Moba _host; + protected final BuffManager _manager; + protected final T _entity; + protected final long _duration; + + private long _start; + + public Buff(Moba host, T entity, long duration) + { + _host = host; + _manager = host.getBuffManager(); + _entity = entity; + _duration = duration; + } + + public abstract void onApply(); + + public abstract void onExpire(); + + final void apply() + { + _start = System.currentTimeMillis(); + UtilServer.RegisterEvents(this); + onApply(); + } + + final void expire() + { + UtilServer.Unregister(this); + onExpire(); + } + + public final T getEntity() + { + return _entity; + } + + public final long getDuration() + { + return _duration; + } + + public final long getStart() + { + return _start; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/BuffManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/BuffManager.java new file mode 100644 index 000000000..66ce3aba8 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/BuffManager.java @@ -0,0 +1,94 @@ +package nautilus.game.arcade.game.games.moba.buff; + +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class BuffManager implements Listener +{ + + private final Map>> _buffs; + + public BuffManager() + { + _buffs = new HashMap<>(); + } + + public void apply(Buff buff) + { + if (UtilPlayer.isSpectator(buff.getEntity())) + { + return; + } + + _buffs.putIfAbsent(buff.getEntity(), new ArrayList<>(3)); + _buffs.get(buff.getEntity()).add(buff); + buff.apply(); + } + + public boolean hasBuff(LivingEntity entity, Class> clazz) + { + if (!_buffs.containsKey(entity)) + { + return false; + } + + for (Buff buff : _buffs.get(entity)) + { + if (buff.getClass().equals(clazz)) + { + return true; + } + } + + return false; + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + Iterator iterator = _buffs.keySet().iterator(); + + while (iterator.hasNext()) + { + LivingEntity entity = iterator.next(); + List> buffs = _buffs.get(entity); + + if (entity.isDead() || !entity.isValid() || UtilPlayer.isSpectator(entity) || entity instanceof Player && !((Player) entity).isOnline()) + { + buffs.forEach(Buff::expire); + iterator.remove(); + continue; + } + + Iterator> buffIterator = buffs.iterator(); + + while (buffIterator.hasNext()) + { + Buff buff = buffIterator.next(); + + if (UtilTime.elapsed(buff.getStart(), buff.getDuration())) + { + buff.expire(); + buffIterator.remove(); + } + } + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffCripple.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffCripple.java new file mode 100644 index 000000000..aa06f1003 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffCripple.java @@ -0,0 +1,39 @@ +package nautilus.game.arcade.game.games.moba.buff.buffs; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.Buff; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class BuffCripple extends Buff +{ + + private static final ItemStack ITEM = new ItemBuilder(Material.IRON_INGOT) + .setTitle(C.cGray + "Crippled") + .build(); + + public static ItemStack getItemRepresentation() + { + return ITEM; + } + + public BuffCripple(Moba host, Player entity, long duration) + { + super(host, entity, duration); + } + + @Override + public void onApply() + { + UtilTextMiddle.display("", C.cRed + "Crippled", 10, 20, 10, _entity); + } + + @Override + public void onExpire() + { + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffPumpkinKing.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffPumpkinKing.java new file mode 100644 index 000000000..13868ec67 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffPumpkinKing.java @@ -0,0 +1,104 @@ +package nautilus.game.arcade.game.games.moba.buff.buffs; + +import mineplex.core.common.util.F; +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.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.Buff; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityEquipment; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.concurrent.TimeUnit; + +public class BuffPumpkinKing extends Buff +{ + + private static final long DURATION = TimeUnit.MINUTES.toMillis(1); + private static final String DAMAGE_REASON = "Pumpkin King Buff"; + private static final double DAMAGE_FACTOR = 1.5; + private static final ItemStack HELMET = new ItemStack(Material.PUMPKIN); + + public BuffPumpkinKing(Moba host, Player entity) + { + super(host, entity, DURATION); + } + + @Override + public void onApply() + { + _entity.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 60 * 20, 1)); + UtilParticle.PlayParticleToAll(ParticleType.LAVA, _entity.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5F, 0.1F, 10, ViewDist.LONG); + _entity.playSound(_entity.getLocation(), Sound.PORTAL_TRAVEL, 1, 0.5F); + _entity.sendMessage(F.main("Game", "You feel the power of the Pumpkin King flow through you. Your damage and regeneration are increased!")); + } + + @Override + public void onExpire() + { + sendFakeHelmet(_entity, _entity.getInventory().getHelmet()); + } + + @EventHandler + public void updateFakeHelmet(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOW) + { + return; + } + + sendFakeHelmet(_entity, HELMET); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void damageIncrease(CustomDamageEvent event) + { + if (event.isCancelled()) + { + return; + } + + LivingEntity damagee = event.GetDamageeEntity(); + Player damager = event.GetDamagerPlayer(true); + + if (damager == null || !damager.equals(_entity)) + { + return; + } + + UtilParticle.PlayParticleToAll(ParticleType.LARGE_SMOKE, damagee.getLocation().add(0, 0.5, 0), 0.25F, 0.25F, 0.25F, 0.1F, 10, ViewDist.NORMAL); + event.AddMod(DAMAGE_REASON, DAMAGE_FACTOR); + } + + private void sendFakeHelmet(Player player, ItemStack itemStack) + { + // Magic number 4 means helmet + PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(player.getEntityId(), 4, CraftItemStack.asNMSCopy(itemStack)); + + for (Player other : Bukkit.getOnlinePlayers()) + { + // Don't send wearer their own data + if (other.equals(player)) + { + continue; + } + + UtilPlayer.sendPacket(other, packet); + } + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffRooting.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffRooting.java new file mode 100644 index 000000000..8c4e862dc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/buff/buffs/BuffRooting.java @@ -0,0 +1,78 @@ +package nautilus.game.arcade.game.games.moba.buff.buffs; + +import mineplex.core.common.events.EntityVelocityChangeEvent; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAction; +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.UtilTextMiddle; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.Buff; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +public class BuffRooting extends Buff +{ + + public BuffRooting(Moba host, Player entity, long duration) + { + super(host, entity, duration); + } + + @Override + public void onApply() + { + UtilAction.zeroVelocity(_entity); + UtilTextMiddle.display("", C.cRed + "Rooted", 10, 20, 10, (Player) _entity); + } + + @Override + public void onExpire() + { + + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, _entity.getLocation().add(0, 0.5, 0), 0.5F, 0.2F, 0.5F, 0.1F, 5, ViewDist.LONG); + } + + @EventHandler + public void velocityApply(EntityVelocityChangeEvent event) + { + if (event.getEntity().equals(_entity)) + { + event.setCancelled(true); + } + } + + @EventHandler + public void move(PlayerMoveEvent event) + { + if (!event.getPlayer().equals(_entity)) + { + return; + } + + Location from = event.getFrom(); + Location to = event.getTo(); + + if (from.getX() == to.getX() && from.getZ() == to.getZ()) + { + return; + } + + event.setTo(from); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/fountain/MobaFountain.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/fountain/MobaFountain.java new file mode 100644 index 000000000..05c8d22da --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/fountain/MobaFountain.java @@ -0,0 +1,91 @@ +package nautilus.game.arcade.game.games.moba.fountain; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.events.PlayerGameRespawnEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +public class MobaFountain implements Listener +{ + + private static final int FOUNTAIN_SIZE_SQUARED = 50; + + private final Moba _host; + private final Map _average; + + public MobaFountain(Moba host) + { + _host = host; + _average = new HashMap<>(); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (GameTeam team : _host.GetTeamList()) + { + _average.put(team, UtilAlg.getAverageLocation(team.GetSpawns())); + } + } + + @EventHandler + public void respawn(PlayerGameRespawnEvent event) + { + Player player = event.GetPlayer(); + + _host.getArcadeManager().GetCondition().Factory().Regen("Fountain", player, null, 3, 9, false, true, false); + } + + @EventHandler + public void updateInFountain(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || !_host.IsLive()) + { + return; + } + + for (Player player : _host.GetPlayers(true)) + { + GameTeam playerTeam = _host.GetTeam(player); + + for (Entry entry : _average.entrySet()) + { + GameTeam team = entry.getKey(); + Location location = entry.getValue(); + + if (UtilMath.offsetSquared(player.getLocation(), location) > FOUNTAIN_SIZE_SQUARED) + { + continue; + } + + if (playerTeam.equals(team)) + { + player.setHealth(Math.min(player.getMaxHealth(), player.getHealth() + 6)); + } + else + { + _host.getArcadeManager().GetDamage().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 10, false, true, true, "Fountain", "Fountain"); + } + } + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/ArrowKBManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/ArrowKBManager.java new file mode 100644 index 000000000..4b4239bbd --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/ArrowKBManager.java @@ -0,0 +1,41 @@ +package nautilus.game.arcade.game.games.moba.general; + +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.metadata.FixedMetadataValue; + +public class ArrowKBManager implements Listener +{ + + private static final String ENTITY_METADATA = "KB"; + private final Moba _host; + + public ArrowKBManager(Moba host) + { + _host = host; + } + + @EventHandler + public void arrowDamage(CustomDamageEvent event) + { + Projectile projectile = event.GetProjectile(); + + if (projectile == null || projectile.getType() != EntityType.ARROW || projectile.hasMetadata(ENTITY_METADATA)) + { + return; + } + + event.SetKnockback(false); + } + + public void allowKnockback(Entity projectile) + { + projectile.setMetadata(ENTITY_METADATA, new FixedMetadataValue(_host.getArcadeManager().getPlugin(), true)); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/BetaManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/BetaManager.java new file mode 100644 index 000000000..f8f08448a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/BetaManager.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.general; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class BetaManager implements Listener +{ + + private static final String MESSAGE = F.main("Game", "You can suggest improvements for the game on our Trello here ") + C.cYellow + "https://trello.com/b/MrxWVhlI/mineplex-heroes-of-gwen-feedback-update"; + private final Moba _host; + + public BetaManager(Moba host) + { + _host = host; + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.MIN_02 || _host.GetState() != GameState.Recruit) + { + return; + } + + Bukkit.broadcastMessage(MESSAGE); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/EnderPearlManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/EnderPearlManager.java new file mode 100644 index 000000000..4daeedeed --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/EnderPearlManager.java @@ -0,0 +1,100 @@ +package nautilus.game.arcade.game.games.moba.general; + +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.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import org.bukkit.Location; +import org.bukkit.entity.EnderPearl; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.projectiles.ProjectileSource; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class EnderPearlManager implements Listener +{ + + private static final int MAX_TICKS = 2 * 20; + private final Map _pearls; + + public EnderPearlManager() + { + _pearls = new HashMap<>(); + } + + @EventHandler + public void projectileLaunch(ProjectileLaunchEvent event) + { + Projectile entity = event.getEntity(); + + if (!(entity instanceof EnderPearl) || !(entity.getShooter() instanceof Player)) + { + return; + } + + Player shooter = (Player) event.getEntity().getShooter(); + + _pearls.put(shooter, event.getEntity()); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _pearls.keySet().iterator(); + + while (iterator.hasNext()) + { + Player shooter = iterator.next(); + Projectile entity = _pearls.get(shooter); + + if (UtilPlayer.isSpectator(shooter)) + { + iterator.remove(); + entity.remove(); + } + else if (entity.getTicksLived() > MAX_TICKS) + { + teleport(shooter, entity); + entity.remove(); + iterator.remove(); + } + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, entity.getLocation(), 0, 0, 0, 0.1F, 3, ViewDist.LONG); + } + } + + @EventHandler + public void projectileHit(ProjectileHitEvent event) + { + ProjectileSource source = event.getEntity().getShooter(); + + if (_pearls.remove(source) != null) + { + teleport((Player) source, event.getEntity()); + } + } + + private void teleport(Player shooter, Projectile entity) + { + Location toTeleport = entity.getLocation(); + Location playerLocation = shooter.getLocation(); + toTeleport.setYaw(playerLocation.getYaw()); + toTeleport.setPitch(playerLocation.getPitch()); + + shooter.teleport(toTeleport); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/MobaDamageManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/MobaDamageManager.java new file mode 100644 index 000000000..e989d5b09 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/general/MobaDamageManager.java @@ -0,0 +1,107 @@ +package nautilus.game.arcade.game.games.moba.general; + +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.condition.Condition; +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import mineplex.minecraft.game.core.condition.events.ConditionApplyEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; + +public class MobaDamageManager implements Listener +{ + + private final Moba _host; + + public MobaDamageManager(Moba host) + { + _host = host; + } + + @EventHandler + public void preventTeamDamage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(); + Player damager = event.GetDamagerPlayer(true); + + if (damagee == null || damager == null) + { + return; + } + + GameTeam damageeTeam = _host.GetTeam(damagee); + GameTeam damagerTeam = _host.GetTeam(damager); + + if (damageeTeam == null || damagerTeam == null) + { + return; + } + + if (damageeTeam.equals(damagerTeam)) + { + event.SetCancelled("Team Damage"); + } + else + { + _host.getScoreboardModule().refreshAsSubject(damagee); + } + } + + @EventHandler + public void preventTeamFire(ConditionApplyEvent event) + { + Condition condition = event.GetCondition(); + + if (condition.GetType() != ConditionType.BURNING) + { + return; + } + + if (condition.GetEnt() == null || condition.GetSource() == null) + { + return; + } + + if (!(condition.GetEnt() instanceof Player && condition.GetSource() instanceof Player)) + { + return; + } + + if (!_host.GetTeam((Player) condition.GetEnt()).equals(_host.GetTeam((Player) condition.GetSource()))) + { + return; + } + + event.setCancelled(true); + } + + @EventHandler + public void updateDamageScoreboard(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + _host.getScoreboardModule().refresh(); + } + + @EventHandler(priority = EventPriority.HIGH) + public void unifyKilledWith(CombatDeathEvent event) + { + String word = event.getKilledWord(); + String[] split = word.split("-"); + + if (word.contains("Click") && split.length > 1) + { + word = split[1].trim(); + event.setKilledWord(word); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/gold/GoldManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/gold/GoldManager.java new file mode 100644 index 000000000..afdd3582d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/gold/GoldManager.java @@ -0,0 +1,179 @@ +package nautilus.game.arcade.game.games.moba.gold; + +import mineplex.core.common.Rank; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.DebugCommand; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.structure.point.CapturePoint; +import nautilus.game.arcade.game.games.moba.structure.point.CapturePointCaptureEvent; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerDestroyEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.HashMap; +import java.util.Map; + +public class GoldManager implements Listener +{ + + private static final int GOLD_PER_5 = 20; + private static final int GOLD_PER_CAPTURE_5 = 5; + private static final int GOLD_PER_CAPTURE_INITIAL = 25; + private static final int GOLD_PER_FIRST_TOWER = 100; + private static final int GOLD_PER_SECOND_TOWER = 250; + + + private final Moba _host; + + private final Map _playerGold; + + public GoldManager(Moba host) + { + _host = host; + + _playerGold = new HashMap<>(); + + host.registerDebugCommand(new DebugCommand("gold", Rank.ADMIN) + { + @Override + public void Execute(Player caller, String[] args) + { + if (args.length < 1) + { + caller.sendMessage(F.main("Debug", "/gold ")); + return; + } + + try + { + int amount = Integer.parseInt(args[0]); + + addGold(caller, amount); + caller.sendMessage(F.main("Debug", "Gave yourself " + F.elem(args[0]) + " gold.")); + } + catch (NumberFormatException e) + { + caller.sendMessage(F.main("Debug", F.elem(args[0]) + " is not a number.")); + } + } + }); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (Player player : _host.GetPlayers(true)) + { + _playerGold.put(player, 0); + } + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _playerGold.remove(event.getPlayer()); + } + + @EventHandler + public void passiveGain(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC_05 || !_host.IsLive()) + { + return; + } + + // Every player passive + for (Player player : _host.GetPlayers(true)) + { + addGold(player, GOLD_PER_5); + } + + // Capture points + for (CapturePoint point : _host.getCapturePointManager().getCapturePoints()) + { + GameTeam owner = point.getOwner(); + + if (owner == null) + { + continue; + } + + for (Player player : owner.GetPlayers(true)) + { + addGold(player, GOLD_PER_CAPTURE_5); + } + } + } + + @EventHandler + public void towerDestroy(TowerDestroyEvent event) + { + for (Player player : _host.GetPlayers(true)) + { + // Don't give the gold to the owners + if (_host.GetTeam(player).equals(event.getTower().getOwner())) + { + continue; + } + + addGold(player, event.getTower().isFirstTower() ? GOLD_PER_FIRST_TOWER : GOLD_PER_SECOND_TOWER, "Destroying a tower"); + } + } + + @EventHandler + public void pointCapture(CapturePointCaptureEvent event) + { + GameTeam team = event.getPoint().getOwner(); + + for (Player player : team.GetPlayers(true)) + { + addGold(player, GOLD_PER_CAPTURE_INITIAL, "Capturing a beacon"); + } + } + + public int getGold(Player player) + { + return _playerGold.get(player); + } + + public void addGold(Player player, int amount) + { + addGold(player, amount, null); + } + + public void addGold(Player player, int amount, String reason) + { + _playerGold.put(player, _playerGold.get(player) + amount); + _host.getArcadeManager().GetStatsManager().incrementStat(player, _host.GetName() + ".GoldEarned", amount); + + if (amount > 20 && reason != null) + { + _host.AddGems(player, (double) amount / 2D, reason, true, true); + player.sendMessage(F.main("Game", C.cGold + "+" + amount + " gold (" + reason + ")" + C.cGray + ".")); + } + } + + public void removeGold(Player player, int amount) + { + _playerGold.put(player, _playerGold.get(player) - amount); + } + + public boolean hasGold(Player player, int amount) + { + return _playerGold.get(player) >= amount; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/AmmoGiveEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/AmmoGiveEvent.java new file mode 100644 index 000000000..9bb26419a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/AmmoGiveEvent.java @@ -0,0 +1,54 @@ +package nautilus.game.arcade.game.games.moba.kit; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class AmmoGiveEvent extends PlayerEvent +{ + + private static final HandlerList _handlers = new HandlerList(); + + private int _ammoToGive; + private int _maxAmmo; + + public AmmoGiveEvent(Player who, int ammoToGive, int maxAmmo) + { + super(who); + + _ammoToGive = ammoToGive; + _maxAmmo = maxAmmo; + } + + public void setAmmoToGive(int ammo) + { + _ammoToGive = ammo; + } + + public int getAmmoToGive() + { + return _ammoToGive; + } + + public void setMaxAmmo(int ammo) + { + _maxAmmo = ammo; + } + + public int getMaxAmmo() + { + return _maxAmmo; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/CooldownCalculateEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/CooldownCalculateEvent.java new file mode 100644 index 000000000..e2df2cc62 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/CooldownCalculateEvent.java @@ -0,0 +1,56 @@ +package nautilus.game.arcade.game.games.moba.kit; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class CooldownCalculateEvent extends PlayerEvent +{ + + private static final HandlerList _handlers = new HandlerList(); + + private final long _initialCooldown; + private final String _ability; + private long _cooldown; + + public CooldownCalculateEvent(Player who, String ability, long cooldown) + { + super(who); + + _initialCooldown = cooldown; + _ability = ability; + _cooldown = cooldown; + } + + public String getAbility() + { + return _ability; + } + + public void setCooldown(long cooldown) + { + _cooldown = cooldown; + } + + public void decreaseCooldown(double factor) + { + _cooldown -= (long) ((double) _initialCooldown * factor); + } + + public long getCooldown() + { + return _cooldown; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroKit.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroKit.java new file mode 100644 index 000000000..0fbecfe73 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroKit.java @@ -0,0 +1,280 @@ +package nautilus.game.arcade.game.games.moba.kit; + +import com.mojang.authlib.GameProfile; +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilGear; +import mineplex.core.common.util.UtilItem; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.disguise.disguises.DisguisePlayer; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.core.utils.UtilGameProfile; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import nautilus.game.arcade.kit.Kit; +import nautilus.game.arcade.kit.KitAvailability; +import nautilus.game.arcade.kit.Perk; +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 java.util.List; + +public class HeroKit extends Kit +{ + + private final MobaRole _role; + + private static final int AMMO_SLOT = 7; + private ItemStack _ammo; + private long _giveTime; + private int _maxAmmo; + private SkinData _skin; + + private static final int RECALL_SLOT = 8; + private static final ItemStack RECALL_ITEM = new ItemBuilder(Material.BED) + .setTitle(C.cGreenB + "Recall to your Base") + .addLore("Clicking this item will teleport you back to your", "base after " + F.time("5") + " seconds.", "Taking damage or moving will cancel", "your teleport.") + .build(); + private static final ItemStack SHOP_ITEM = new ItemBuilder(Material.GOLD_INGOT) + .setTitle(C.cGold + "Open Gold Upgrades") + .addLore("Click to open the Gold Upgrades", "shop while you are respawning.") + .build(); + + private boolean _visible = true; + + public HeroKit(ArcadeManager manager, String name, Perk[] kitPerks, MobaRole role, SkinData skin) + { + super(manager, name, KitAvailability.Free, new String[0], kitPerks, null, null); + + _role = role; + _maxAmmo = 64; + _skin = skin; + } + + public MobaRole getRole() + { + return _role; + } + + public ItemStack getAmmo() + { + return _ammo; + } + + public void setAmmo(ItemStack ammo, long giveTime) + { + _ammo = ammo; + _giveTime = giveTime; + } + + public void setMaxAmmo(int max) + { + _maxAmmo = max; + } + + public boolean useAmmo(Player player, int amount) + { + ItemStack itemStack = player.getInventory().getItem(AMMO_SLOT); + + if (itemStack == null) + { + return false; + } + + int newAmount = itemStack.getAmount() - amount; + + if (itemStack.getAmount() < amount) + { + return false; + } + + if (newAmount == 0) + { + player.getInventory().remove(itemStack); + } + else + { + itemStack.setAmount(newAmount); + } + return true; + } + + @EventHandler + public void giveAmmo(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST || Manager.GetGame() == null || !Manager.GetGame().IsLive() || _ammo == null) + { + return; + } + + for (Player player : Manager.GetGame().GetPlayers(true)) + { + if (!HasKit(player) || UtilPlayer.isSpectator(player)) + { + continue; + } + + long giveTime = _giveTime; + + if (!Recharge.Instance.usable(player, MobaConstants.AMMO)) + { + continue; + } + + CooldownCalculateEvent cooldownEvent = new CooldownCalculateEvent(player, MobaConstants.AMMO, giveTime); + UtilServer.CallEvent(cooldownEvent); + + if (!Recharge.Instance.use(player, MobaConstants.AMMO, cooldownEvent.getCooldown(), false, false)) + { + continue; + } + + giveAmmo(player, 1); + } + } + + public void giveAmmo(Player player, int amount) + { + ItemStack itemStack = player.getInventory().getItem(AMMO_SLOT); + + AmmoGiveEvent event = new AmmoGiveEvent(player, amount, _maxAmmo); + UtilServer.CallEvent(event); + + if (itemStack == null) + { + itemStack = _ammo; + player.getInventory().setItem(AMMO_SLOT, itemStack); + return; + } + + if (itemStack.getAmount() >= event.getMaxAmmo()) + { + return; + } + + itemStack.setAmount(itemStack.getAmount() + event.getAmmoToGive()); + } + + @Override + public void GiveItems(Player player) + { + PlayerInventory inventory = player.getInventory(); + + // Give standard items + inventory.setItem(AMMO_SLOT, _ammo); + //inventory.setItem(RECALL_SLOT, RECALL_ITEM); + inventory.setItem(RECALL_SLOT, SHOP_ITEM); + + Moba game = (Moba) Manager.GetGame(); + List items = game.getShop().getOwnedItems(player); + + for (MobaItem item : items) + { + ItemStack itemstack = item.getItem(); + + // Give armour + if (UtilItem.isHelmet(itemstack)) + { + inventory.setHelmet(itemstack); + } + else if (UtilItem.isChestplate(itemstack)) + { + inventory.setChestplate(itemstack); + } + else if (UtilItem.isLeggings(itemstack)) + { + inventory.setLeggings(itemstack); + } + else if (UtilItem.isBoots(itemstack)) + { + inventory.setBoots(itemstack); + } + + // Give consumable items + else if (!UtilItem.isSword(itemstack) && !UtilGear.isBow(itemstack)) + { + // Keep moving left from the ammo slot until a free slot is available + for (int i = AMMO_SLOT - 1; i >= GetPerks().length - 1; i--) + { + ItemStack consumable = inventory.getItem(i); + + if (consumable == null) + { + inventory.setItem(i, itemstack); + break; + } + else if (consumable.isSimilar(itemstack)) + { + consumable.setAmount(consumable.getAmount() + 1); + break; + } + } + } + } + + // Give all skill related items + for (Perk perk : GetPerks()) + { + if (!(perk instanceof HeroSkill)) + { + continue; + } + + HeroSkill skill = (HeroSkill) perk; + + if (skill.isOnCooldown(player)) + { + player.getInventory().setItem(skill.getSlot(), skill.getCooldownItem()); + } + else + { + skill.giveItem(player); + } + } + } + + @Override + public void GiveItemsCall(Player player) + { + super.GiveItemsCall(player); + + disguise(player); + } + + public void disguise(Player player) + { + disguise(player, _skin); + } + + public void disguise(Player player, SkinData skin) + { + GameProfile profile = UtilGameProfile.getGameProfile(player); + profile.getProperties().clear(); + profile.getProperties().put("textures", skin.getProperty()); + DisguisePlayer disguise = new DisguisePlayer(player, profile); + disguise.showInTabList(true, 0); + + Manager.GetDisguise().disguise(disguise); + } + + public boolean isVisible() + { + return _visible; + } + + public void setVisible(boolean visible) + { + _visible = visible; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroSkill.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroSkill.java new file mode 100644 index 000000000..59cdd544a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/HeroSkill.java @@ -0,0 +1,387 @@ +package nautilus.game.arcade.game.games.moba.kit; + +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.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.PlayerKitGiveEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.buffs.BuffCripple; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import nautilus.game.arcade.kit.Kit; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class HeroSkill extends Perk +{ + + private ItemStack _item; + private ItemStack _cooldownItem; + private final int _slot; + private final ActionType _actionType; + private boolean _sneakActivate; + private boolean _dropItemActivate; + + protected HeroKit _kit; + private long _cooldown; + + private final Map _lastSkill = new HashMap<>(); + + public HeroSkill(String name, String[] perkDesc) + { + this(name, perkDesc, null, -1, null); + } + + public HeroSkill(String name, String[] perkDesc, ItemStack itemStack, int slot, ActionType actionType) + { + super(name, perkDesc); + + _item = itemStack; + _slot = slot; + _actionType = actionType; + } + + public void setSneakActivate(boolean activate) + { + _sneakActivate = activate; + } + + public void setDropItemActivate(boolean activate) + { + _dropItemActivate = activate; + } + + protected void setCooldown(long cooldown) + { + _cooldown = cooldown; + } + + private void prettifyItems() + { + String action = null; + + if (_actionType == ActionType.ANY) + { + action = "Click"; + } + if (_actionType == ActionType.L) + { + action = "Left Click"; + } + else if (_actionType == ActionType.R) + { + action = "Right Click"; + } + + if (_sneakActivate) + { + action += "/Sneak"; + } + + if (_dropItemActivate) + { + action += "/Drop Item"; + } + + _item = new ItemBuilder(_item) + .setTitle((action != null ? C.cYellowB + action + C.cGray + " - " : "") + C.cGreenB + GetName()) + .addLore(GetDesc()) + .setUnbreakable(true) + .build(); + + _cooldownItem = new ItemBuilder(Material.INK_SACK, (byte) 8) + .setTitle(C.cRed + GetName()) + .addLore(GetDesc()) + .setUnbreakable(true) + .build(); + } + + @Override + public void SetHost(Kit kit) + { + super.SetHost(kit); + + _kit = (HeroKit) kit; + prettifyItems(); + } + + @EventHandler + public void giveItem(PlayerKitGiveEvent event) + { + Player player = event.getPlayer(); + + if (!hasPerk(player)) + { + return; + } + + if (isOnCooldown(player)) + { + player.getInventory().setItem(_slot, _cooldownItem); + } + else + { + giveItem(player); + } + } + + @EventHandler + public void clearCooldowns(PlayerQuitEvent event) + { + UUID key = event.getPlayer().getUniqueId(); + + _lastSkill.remove(key); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + } + + protected boolean isSkillItem(PlayerInteractEvent event) + { + if (event.isCancelled()) + { + return false; + } + + if (!UtilEvent.isAction(event, _actionType)) + { + if (_actionType != null || event.getAction() == Action.PHYSICAL) + { + return false; + } + } + + Player player = event.getPlayer(); + ItemStack itemStack = event.getItem(); + + if (!hasPerk(player) || UtilPlayer.isSpectator(player) || itemStack == null) + { + return false; + } + + return itemStack.isSimilar(_item); + + } + + protected boolean isSkillSneak(PlayerToggleSneakEvent event) + { + if (event.isCancelled() || !event.isSneaking()) + { + return false; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getInventory().getItem(_slot); + + if (!hasPerk(player) || UtilPlayer.isSpectator(player) || itemStack == null) + { + return false; + } + + return itemStack.isSimilar(_item); + + } + + @EventHandler + public void dropTrigger(PlayerDropItemEvent event) + { + Player player = event.getPlayer(); + + if (!_dropItemActivate || !hasPerk(player)) + { + return; + } + + // Call interact with a fake PlayerInteractEvent + PlayerInteractEvent interactEvent = new PlayerInteractEvent(event.getPlayer(), Action.RIGHT_CLICK_AIR, player.getInventory().getItem(_slot), null, null); + + // You actually need to setCancelled false here otherwise it remains cancelled by default when the clicked block is null, thanks Bukkit + interactEvent.setCancelled(false); + interact(interactEvent); + } + + + public void useSkill(Player player) + { + _lastSkill.put(player.getUniqueId(), System.currentTimeMillis()); + if (_cooldown > 0 && !UtilPlayer.isSpectator(player)) + { + player.getInventory().setItem(_slot, _cooldownItem); + } + } + + protected void broadcast(Player player) + { + Moba game = (Moba) Manager.GetGame(); + GameTeam team = game.GetTeam(player); + HeroKit kit = game.getMobaData(player).getKit(); + + if (team == null || kit == null) + { + return; + } + + game.Announce(team.GetColor() + C.Bold + player.getName() + " " + kit.getRole().getChatColor() + kit.GetName() + C.cWhiteB + " activated their " + team.GetColor() + C.Bold + GetName() + C.cWhiteB + ".", false); + player.getWorld().playSound(player.getLocation(), Sound.NOTE_PLING, 10, 0.5F); + } + + @EventHandler + public void updateCooldowns(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST || _item == null) + { + return; + } + + Moba moba = (Moba) Manager.GetGame(); + long current = System.currentTimeMillis(); + + for (Player player : Manager.GetGame().GetPlayers(true)) + { + if (!hasPerk(player) || UtilPlayer.isSpectator(player) || !_lastSkill.containsKey(player.getUniqueId())) + { + continue; + } + + ItemStack itemStack = player.getInventory().getItem(_slot); + long start = _lastSkill.get(player.getUniqueId()); + long cooldown = _cooldown; + + // Modify the cooldown with respect to the upgrade items purchased from the shop + CooldownCalculateEvent cooldownEvent = new CooldownCalculateEvent(player, GetName(), cooldown); + UtilServer.CallEvent(cooldownEvent); + + cooldown = cooldownEvent.getCooldown(); + + boolean done = UtilTime.elapsed(start, cooldown); + + // If the player is crippled say they are + if (moba.getBuffManager().hasBuff(player, BuffCripple.class)) + { + player.getInventory().setItem(_slot, BuffCripple.getItemRepresentation()); + continue; + } + + if (done) + { + _lastSkill.remove(player.getUniqueId()); + giveItem(player); + } + else + { + long timeDiff = current - start; + // Work out the itemstack amount based on the cooldowns. + // Adding 1 as due to the nature of cooldowns it seems to take much longer to go + // from 2 -> 1 -> 0 as the itemstack doesn't change + double amount = (cooldown / 1000) - Math.ceil((double) timeDiff / 1000) + 1; + + if (itemStack == null) + { + itemStack = _cooldownItem; + } + + itemStack.setAmount((int) amount); + } + } + } + + public void giveItem(Player player) + { + player.getInventory().setItem(_slot, _item); + } + + public void useActiveSkill(Player player, long time) + { + useActiveSkill(null, player, time); + } + + public void useActiveSkill(Runnable complete, Player player, long time) + { + long ticks = (long) (time / 1000D); + ItemStack itemStack = player.getInventory().getItem(getSlot()); + itemStack.setAmount((int) (ticks / 20D)); + UtilInv.addDullEnchantment(itemStack); + Recharge.Instance.useForce(player, GetName(), time, true); + Recharge.Instance.setDisplayForce(player, GetName(), true); + + Manager.runSyncTimer(new BukkitRunnable() + { + int iterations = 0; + + @Override + public void run() + { + if (iterations++ > ticks) + { + if (complete != null) + { + complete.run(); + } + useSkill(player); + cancel(); + return; + } + + itemStack.setAmount(itemStack.getAmount() - 1); + } + }, 0, 20); + } + + public void resetCooldown(Player player) + { + _lastSkill.put(player.getUniqueId(), 0L); + } + + protected boolean isTeamDamage(LivingEntity damagee, LivingEntity damager) + { + if (!(damager instanceof Player)) + { + return false; + } + + GameTeam team = Manager.GetGame().GetTeam((Player) damager); + + return team != null && MobaUtil.isTeamEntity(damagee, team); + + } + + public int getSlot() + { + return _slot; + } + + public ItemStack getCooldownItem() + { + return _cooldownItem; + } + + public boolean isOnCooldown(Player player) + { + return _lastSkill.containsKey(player.getUniqueId()); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/KitPlayer.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/KitPlayer.java new file mode 100644 index 000000000..41d6428c2 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/KitPlayer.java @@ -0,0 +1,27 @@ +package nautilus.game.arcade.game.games.moba.kit; + +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.kit.Kit; +import nautilus.game.arcade.kit.KitAvailability; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +public class KitPlayer extends Kit +{ + + private static final String[] DESCRIPTION = { + + }; + + public KitPlayer(ArcadeManager manager) + { + super(manager, "Player", KitAvailability.Free, DESCRIPTION, new Perk[0], EntityType.PIG, null); + } + + @Override + public void GiveItems(Player player) + { + + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/RoleSelectEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/RoleSelectEvent.java new file mode 100644 index 000000000..d4c170c40 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/RoleSelectEvent.java @@ -0,0 +1,61 @@ +package nautilus.game.arcade.game.games.moba.kit; + +import mineplex.core.common.entity.ClientArmorStand; +import nautilus.game.arcade.game.games.moba.MobaRole; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class RoleSelectEvent extends PlayerEvent implements Cancellable +{ + + private static final HandlerList _handlers = new HandlerList(); + + private final ClientArmorStand _stand; + private final MobaRole _role; + + private boolean _cancel; + + public RoleSelectEvent(Player who, ClientArmorStand stand, MobaRole role) + { + super(who); + + _stand = stand; + _role = role; + } + + public ClientArmorStand getStand() + { + return _stand; + } + + public MobaRole getRole() + { + return _role; + } + + @Override + public boolean isCancelled() + { + return _cancel; + } + + @Override + public void setCancelled(boolean b) + { + _cancel = b; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/HeroAnath.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/HeroAnath.java new file mode 100644 index 000000000..6023bd3ed --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/HeroAnath.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.kit.anath; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class HeroAnath extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillFireProjectile(0), + new SkillBurnBeam(1), + new SkillFlameDash(2), + new SkillMeteor(3) + }; + + private static final ItemStack AMMO = new ItemBuilder(Material.BLAZE_POWDER) + .setTitle(C.cYellowB + "Embers") + .build(); + + public HeroAnath(ArcadeManager manager) + { + super(manager, "Anath", PERKS, MobaRole.MAGE, SkinData.ANATH); + + setAmmo(AMMO, 1000); + setMaxAmmo(4); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillBurnBeam.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillBurnBeam.java new file mode 100644 index 000000000..7938148b3 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillBurnBeam.java @@ -0,0 +1,97 @@ +package nautilus.game.arcade.game.games.moba.kit.anath; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilServer; +import mineplex.core.common.util.particles.effects.LineParticle; +import mineplex.core.recharge.Recharge; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +public class SkillBurnBeam extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Fires a single, vertical beam of Flames which move forward in a straight.", + "It passes through enemies and structures dealing damage", + "to anything it passes through." + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FIREBALL); + + public SkillBurnBeam(int slot) + { + super("Burn Beam", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(10000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + Vector direction = player.getLocation().getDirection().setY(0); + + player.getWorld().playSound(player.getLocation(), Sound.BLAZE_BREATH, 2, 0.5F); + + useSkill(player); + + LineParticle particle = new LineParticle(player.getLocation().add(direction), direction, 0.2, 9, null, ParticleType.LAVA, UtilServer.getPlayers()); + + particle.setIgnoreAllBlocks(true); + + Manager.runSyncTimer(new BukkitRunnable() + { + @Override + public void run() + { + for (int i = 0; i < 3; i++) + { + if (particle.update()) + { + cancel(); + return; + } + else + { + UtilParticle.PlayParticleToAll(ParticleType.FLAME, particle.getLastLocation().clone().add(0, 5, 0), 0.4F, 5, 0.4F, 0.05F, 30, ViewDist.LONG); + } + } + + if (Math.random() < 0.1) + { + particle.getLastLocation().getWorld().playSound(particle.getLastLocation(), Sound.GHAST_FIREBALL, 2, 0.5F); + } + + for (LivingEntity entity : UtilEnt.getInRadius(particle.getLastLocation(), 2).keySet()) + { + if (entity.equals(player) || !Recharge.Instance.use(player, GetName() + entity.getUniqueId() + player.getName(), 2000, false, false)) + { + continue; + } + + entity.getLocation().getWorld().playSound(entity.getLocation(), Sound.EXPLODE, 2, 0.5F); + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, 15, true, true, false, UtilEnt.getName(player), GetName()); + } + } + }, 0, 1); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFireProjectile.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFireProjectile.java new file mode 100644 index 000000000..59b39a822 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFireProjectile.java @@ -0,0 +1,52 @@ +package nautilus.game.arcade.game.games.moba.kit.anath; + +import mineplex.core.common.util.UtilEvent.ActionType; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import org.bukkit.Material; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +public class SkillFireProjectile extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Fires an Ember at high speed in front of you.", + "Any enemies it collides with take damage and are set on fire." + }; + private static final int DAMAGE = 5; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.BLAZE_ROD); + + public SkillFireProjectile(int slot) + { + super("Flame Wand", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + if (!_kit.useAmmo(player, 1)) + { + return; + } + + Vector direction = player.getLocation().getDirection().multiply(1.25); + Item item = player.getWorld().dropItem(player.getEyeLocation().add(direction), _kit.getAmmo()); + item.setVelocity(direction); + + Manager.GetFire().Add(item, player, 3, 0, 1, DAMAGE, MobaConstants.BASIC_ATTACK, false); + ((Moba) Manager.GetGame()).getTowerManager().addProjectile(player, item, DAMAGE); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFlameDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFlameDash.java new file mode 100644 index 000000000..e51aa1004 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillFlameDash.java @@ -0,0 +1,45 @@ +package nautilus.game.arcade.game.games.moba.kit.anath; + +import mineplex.core.common.util.UtilBlock; +import nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class SkillFlameDash extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Dash along the ground, leaving fire behind you.", + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillFlameDash(int slot) + { + super("Flame Dash", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(12000); + + _collide = false; + _velocityTime = 600; + _velocityStopOnEnd = true; + _horizontial = true; + } + + @Override + public void dashTick(Player player) + { + Block block = player.getLocation().getBlock(); + + while (!UtilBlock.solid(block)) + { + block = block.getRelative(BlockFace.DOWN); + } + + Block fBlock = block; + Manager.runSyncLater(() -> Manager.GetBlockRestore().add(fBlock.getRelative(BlockFace.UP), Material.FIRE.getId(), (byte) 0, 5000), 10); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillMeteor.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillMeteor.java new file mode 100644 index 000000000..dc255d790 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/anath/SkillMeteor.java @@ -0,0 +1,188 @@ +package nautilus.game.arcade.game.games.moba.kit.anath; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.particles.ColoredParticle; +import mineplex.core.common.util.particles.DustSpellColor; +import mineplex.core.projectile.IThrown; +import mineplex.core.projectile.ProjectileUser; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.kit.perks.data.MeteorShowerData; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.LargeFireball; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.awt.*; +import java.util.HashSet; +import java.util.Set; + +public class SkillMeteor extends HeroSkill implements IThrown +{ + + private static final String[] DESCRIPTION = { + "Shoot out a Block of Netherrack which is placed where it lands.", + "Meteors rain from the sky around the block.", + "Enemies within the area are damaged.", + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + + private final Set _data = new HashSet<>(); + + public SkillMeteor(int slot) + { + super("Meteor Shower", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + if (!Recharge.Instance.use(player, GetName() + "Trigger", 2000, false, false)) + { + return; + } + + for (MeteorShowerData data : _data) + { + if (data.Shooter.equals(player)) + { + return; + } + } + + FallingBlock block = player.getWorld().spawnFallingBlock(player.getEyeLocation().add(player.getLocation().getDirection()), Material.NETHERRACK, (byte) 0); + block.setVelocity(player.getLocation().getDirection()); + + Manager.GetProjectile().AddThrow(block, player, this, 2000, true, true, true, false, 0.5F); + + broadcast(player); + useActiveSkill(player, 7000); + } + + @EventHandler + public void entityChangeBlock(EntityChangeBlockEvent event) + { + if (event.getEntity() instanceof FallingBlock) + { + event.getEntity().remove(); + event.setCancelled(true); + } + } + + @EventHandler + public void updateShower(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + _data.removeIf(MeteorShowerData::update); + + for (MeteorShowerData data : _data) + { + Location location = data.Target; + GameTeam team = Manager.GetGame().GetTeam(data.Shooter); + DustSpellColor colour = new DustSpellColor(team.GetColor() == ChatColor.RED ? Color.RED : Color.CYAN); + + for (double theta = 0; theta < 2 * Math.PI; theta += Math.PI / 100) + { + double x = 10 * Math.sin(theta); + double z = 10 * Math.cos(theta); + + location.add(x, 0.25, z); + + new ColoredParticle(ParticleType.RED_DUST, colour, location).display(ViewDist.LONG); + + location.subtract(x, 0.25, z); + } + + for (LivingEntity nearby : UtilEnt.getInRadius(location, 10).keySet()) + { + if (isTeamDamage(data.Shooter, nearby)) + { + continue; + } + + nearby.setFireTicks(20); + Manager.GetDamage().NewDamageEvent(nearby, data.Shooter, null, DamageCause.CUSTOM, 2, true, true, false, UtilEnt.getName(data.Shooter), GetName()); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void projectileHit(EntityExplodeEvent event) + { + if (event.getEntity() instanceof LargeFireball) + { + event.blockList().clear(); + } + } + + @Override + public void Collide(LivingEntity target, Block block, ProjectileUser data) + { + Entity thrown = data.getThrown(); + + startShower(data); + + thrown.remove(); + } + + @Override + public void Idle(ProjectileUser data) + { + Expire(data); + } + + @Override + public void Expire(ProjectileUser data) + { + for (MeteorShowerData showerData : _data) + { + if (showerData.Shooter.equals(data.getThrower())) + { + return; + } + } + + startShower(data); + data.getThrown().remove(); + } + + private void startShower(ProjectileUser data) + { + Manager.GetBlockRestore().add(data.getThrown().getLocation().getBlock(), Material.NETHERRACK.getId(), (byte) 0, 6000); + _data.add(new MeteorShowerData((Player) data.getThrower(), data.getThrown().getLocation(), 6000)); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/HeroBardolf.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/HeroBardolf.java new file mode 100644 index 000000000..d28975e95 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/HeroBardolf.java @@ -0,0 +1,289 @@ +package nautilus.game.arcade.game.games.moba.kit.bardolf; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillSword; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HeroBardolf extends HeroKit +{ + + private static final int MIN_DIST_SQUARED = 2; + private static final int MAX_DIST_SQUARED = 100; + + private final List _data; + + private static final Perk[] PERKS = { + new SkillSword(0), + new SkillSummonWolf(1), + new SkillWolfPounce(2), + new SkillFullMoon(3) + }; + + public HeroBardolf(ArcadeManager manager) + { + super(manager, "Bardolf", PERKS, MobaRole.ASSASSIN, SkinData.BARDOLF); + + _data = new ArrayList<>(2); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _data.removeIf(data -> data.getOwner().equals(event.getPlayer())); + } + + @EventHandler + public void updateWolves(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK || !Manager.GetGame().IsLive()) + { + return; + } + + for (WolfData data : _data) + { + data.getWolves().removeIf(wolf -> wolf.isDead() || !wolf.isValid()); + + data.getWolves().forEach(wolf -> + { + if (data.getOverrideTarget().containsKey(wolf)) + { + UtilEnt.CreatureMoveFast(wolf, data.getOverrideTarget().get(wolf), data.isUltimate() ? 2F : 1.5F); + return; + } + + double ownerOffset = UtilMath.offsetSquared(data.getOwner(), wolf); + + if (wolf.getTarget() != null) + { + LivingEntity target = wolf.getTarget(); + + if (UtilPlayer.isSpectator(target) || target.isDead() || !target.isValid()) + { + wolf.setTarget(null); + return; + } + + UtilEnt.CreatureMoveFast(wolf, wolf.getTarget().getLocation(), data.isUltimate() ? 2F : 1.5F); + + if (UtilMath.offsetSquared(wolf.getTarget(), wolf) < 9 && Recharge.Instance.use(data.getOwner(), "Wolf" + wolf.getTarget().getUniqueId(), 500, false, false)) + { + Manager.GetDamage().NewDamageEvent(wolf.getTarget(), data.getOwner(), null, DamageCause.CUSTOM, 2, true, true, false, data.getOwner().getName(), "Wolf"); + } + } + else if (ownerOffset > MAX_DIST_SQUARED) + { + wolf.teleport(data.getOwner()); + } + else if (ownerOffset > MIN_DIST_SQUARED) + { + UtilEnt.CreatureMoveFast(wolf, data.getOwner().getLocation(), data.isUltimate() ? 2F : 1.5F); + } + }); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void updateTarget(CustomDamageEvent event) + { + if (event.isCancelled()) + { + return; + } + + Player damager = event.GetDamagerPlayer(true); + WolfData data = getWolfData(damager); + + if (damager == null || data == null) + { + return; + } + + for (Wolf wolf : data.getWolves()) + { + wolf.setTarget(event.GetDamageeEntity()); + } + } + + @EventHandler + public void preventTeamDamage(CustomDamageEvent event) + { + if (event.isCancelled()) + { + return; + } + + LivingEntity damagee = event.GetDamageeEntity(); + LivingEntity damager = event.GetDamagerEntity(true); + WolfData data = getWolfData(damagee); + + if (data == null || !(damager instanceof Player)) + { + return; + } + GameTeam team = Manager.GetGame().GetTeam((Player) damager); + + if (team != null && MobaUtil.isTeamEntity(damagee, team)) + { + event.SetCancelled("Team Wolf"); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void entityDeath(EntityDeathEvent event) + { + for (WolfData data : _data) + { + if (data.getWolves().contains(event.getEntity())) + { + event.setDroppedExp(0); + event.getDrops().clear(); + } + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + WolfData data = getWolfData(event.getEntity()); + + if (data == null) + { + return; + } + + data.getWolves().forEach(Entity::remove); + } + + public WolfData getWolfData(Player player) + { + if (player == null) + { + return null; + } + + for (WolfData data : _data) + { + if (data.getOwner().equals(player)) + { + return data; + } + } + + if (Manager.GetGame().GetKit(player).equals(this)) + { + WolfData data = new WolfData(player); + _data.add(data); + return data; + } + + return null; + } + + public WolfData getWolfData(LivingEntity entity) + { + if (entity == null) + { + return null; + } + + for (WolfData data : _data) + { + if (data.getOwner().equals(entity)) + { + return data; + } + + for (Wolf wolf : data.getWolves()) + { + if (wolf.equals(entity)) + { + return data; + } + } + } + + return null; + } + + class WolfData + { + + private Player _owner; + private List _wolves; + private final Map _overrideTarget; + private boolean _ultimate; + private float _lastSpeedIncrease; + + WolfData(Player owner) + { + _owner = owner; + _wolves = new ArrayList<>(5); + _overrideTarget = new HashMap<>(5); + } + + public Player getOwner() + { + return _owner; + } + + public List getWolves() + { + return _wolves; + } + + public Map getOverrideTarget() + { + return _overrideTarget; + } + + public void setUltimate(boolean ultimate) + { + _ultimate = ultimate; + } + + public boolean isUltimate() + { + return _ultimate; + } + + public void setLastSpeedIncrease(float increase) + { + _lastSpeedIncrease = increase; + } + + public float getLastSpeedIncrease() + { + return _lastSpeedIncrease; + } + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillFullMoon.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillFullMoon.java new file mode 100644 index 000000000..c68fab17d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillFullMoon.java @@ -0,0 +1,118 @@ +package nautilus.game.arcade.game.games.moba.kit.bardolf; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.bardolf.HeroBardolf.WolfData; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class SkillFullMoon extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Turns the character into a Werewolf.", + "He gains +1 attack Damage and +5% Movement speed for each Wolf alive in his pack.", + "The Wolves gain movement speed to catch up and are healed to their full HP.", + "As wolves die his power decreases.", + "All Wolves in the pack die after the ultimate ends" + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + private static final long DURATION = TimeUnit.SECONDS.toMillis(10); + private static final int HEALTH = 20; + private static final float SPEED_FACTOR = 0.05F; + + private final Set _active = new HashSet<>(); + + public SkillFullMoon(int slot) + { + super("Full Moon", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if (!isSkillItem(event) || _active.contains(player)) + { + return; + } + + HeroBardolf kit = (HeroBardolf) Kit; + WolfData data = kit.getWolfData(player); + + if (data == null) + { + return; + } + + _active.add(player); + Manager.GetGame().WorldTimeSet = 18000; + player.getWorld().strikeLightningEffect(player.getLocation()); + kit.disguise(player, SkinData.BARDOLF_WEREWOLF); + data.setUltimate(true); + + float speedIncrease = (float) data.getWolves().size() * SPEED_FACTOR; + data.setLastSpeedIncrease(speedIncrease); + + player.setWalkSpeed(player.getWalkSpeed() + speedIncrease); + for (Wolf wolf : data.getWolves()) + { + wolf.setMaxHealth(HEALTH); + wolf.setHealth(wolf.getMaxHealth()); + wolf.setTamed(false); + wolf.setAngry(true); + wolf.getWorld().playSound(wolf.getLocation(), Sound.WOLF_GROWL, 1, 1); + } + + broadcast(player); + useActiveSkill(() -> + { + _active.remove(player); + Manager.GetGame().WorldTimeSet = 12000; + data.setUltimate(false); + kit.disguise(player); + player.setWalkSpeed(player.getWalkSpeed() - data.getLastSpeedIncrease()); + + for (Wolf wolf : data.getWolves()) + { + wolf.setHealth(0); + } + + }, player, DURATION); + } + + @EventHandler + public void damagePlayer(CustomDamageEvent event) + { + LivingEntity damagerEntity = event.GetDamagerEntity(true); + Player damagerPlayer = event.GetDamagerPlayer(true); + WolfData data = ((HeroBardolf) Kit).getWolfData(damagerEntity); + + if (data == null) + { + return; + } + + // Player Damage + if (damagerPlayer != null && _active.contains(damagerPlayer)) + { + event.AddMod(GetName(), data.getWolves().size()); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillSummonWolf.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillSummonWolf.java new file mode 100644 index 000000000..d0e43367b --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillSummonWolf.java @@ -0,0 +1,124 @@ +package nautilus.game.arcade.game.games.moba.kit.bardolf; + +import mineplex.core.common.util.F; +import mineplex.core.common.util.SpigotUtil; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.bardolf.HeroBardolf.WolfData; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +public class SkillSummonWolf extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Click to summon a Wolf to your pack.", + "Wolves are tamed and will attack your target or people who damage you.", + "Wolves are weak and can be killed.", + "Maximum of 5." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.BONE); + private static final int MAX_WOLVES = 5; + private static final int HEALTH = 6; + + public SkillSummonWolf(int slot) + { + super("Summon Wolf", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + setCooldown(5000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if (!isSkillItem(event)) + { + return; + } + + WolfData data = ((HeroBardolf) Kit).getWolfData(player); + + if (data == null) + { + return; + } + else if (data.getWolves().size() == MAX_WOLVES) + { + player.sendMessage(F.main("Game", "You have already summoned the maximum amount of wolves.")); + return; + } + else if (data.isUltimate()) + { + player.sendMessage(F.main("Game", "You cannot summon new wolves right now.")); + return; + } + + Game game = Manager.GetGame(); + GameTeam team = game.GetTeam(player); + + if (team == null) + { + return; + } + + game.CreatureAllowOverride = true; + + Wolf wolf = player.getWorld().spawn(player.getLocation(), Wolf.class); + DyeColor dyeColor = team.GetColor() == ChatColor.RED ? DyeColor.RED : DyeColor.BLUE; + + wolf.setCollarColor(dyeColor); + wolf.setTamed(true); + SpigotUtil.setOldOwner_RemoveMeWhenSpigotFixesThis(wolf, player); + wolf.setOwner(player); + wolf.setHealth(HEALTH); + wolf.setMaxHealth(HEALTH); + UtilEnt.vegetate(wolf); + MobaUtil.setTeamEntity(wolf, team); + + player.getWorld().playSound(player.getLocation(), Sound.WOLF_BARK, 1, 1.1F); + + data.getWolves().add(wolf); + + game.CreatureAllowOverride = false; + + useSkill(player); + } + + @EventHandler + public void updateWolfItem(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + HeroBardolf kit = (HeroBardolf) Kit; + + for (Player player : Manager.GetGame().GetPlayers(true)) + { + WolfData data = kit.getWolfData(player); + ItemStack itemStack = player.getInventory().getItem(getSlot()); + + if (data == null || itemStack == null || itemStack.getType() != SKILL_ITEM.getType()) + { + continue; + } + + itemStack.setAmount(data.getWolves().size()); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillWolfPounce.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillWolfPounce.java new file mode 100644 index 000000000..e69fdc4c0 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bardolf/SkillWolfPounce.java @@ -0,0 +1,169 @@ +package nautilus.game.arcade.game.games.moba.kit.bardolf; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.bardolf.HeroBardolf.WolfData; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public class SkillWolfPounce extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Dash into the air", + "Your wolves will follow you." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + private static final int COOLDOWN = 7000; + + private final Set _data = new HashSet<>(2); + + public SkillWolfPounce(int slot) + { + super("Wolf Pounce", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(COOLDOWN); + setSneakActivate(true); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _data.removeIf(data -> data.Leader.equals(event.getPlayer())); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @EventHandler + public void toggleSneak(PlayerToggleSneakEvent event) + { + if (!isSkillSneak(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @Override + public void useSkill(Player player) + { + super.useSkill(player); + + WolfData data = ((HeroBardolf) Kit).getWolfData(player); + + if (data == null) + { + return; + } + + for (Wolf wolf : data.getWolves()) + { + data.getOverrideTarget().put(wolf, player.getLocation()); + } + + Vector direction = player.getLocation().getDirection(); + direction.setY(Math.max(0.8, direction.getY())); + _data.add(new PounceData(player, data, direction)); + + UtilAction.velocity(player, direction); + + player.getWorld().playSound(player.getLocation(), Sound.WOLF_BARK, 2, 1F); + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, player.getLocation().add(0, 0.6, 0), 0.5F, 0.5F, 0.5F, 0.1F, 15, ViewDist.LONG); + } + + @EventHandler + public void updateWolves(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + PounceData data = iterator.next(); + + for (Wolf wolf : data.WolfData.getWolves()) + { + // Wolf has already leaped + if (data.LeapedWolves.contains(wolf) || UtilMath.offsetSquared(data.Target, wolf.getLocation()) > 4) + { + continue; + } + + data.LeapedWolves.add(wolf); + wolf.setVelocity(data.Direction); + wolf.getWorld().playSound(wolf.getLocation(), Sound.WOLF_WHINE, 1, 1.5F); + data.WolfData.getOverrideTarget().remove(wolf); + } + + if (UtilTime.elapsed(data.Time, COOLDOWN - 500)) + { + iterator.remove(); + data.WolfData.getOverrideTarget().clear(); + } + } + } + + private class PounceData + { + + Player Leader; + WolfData WolfData; + Location Target; + Vector Direction; + long Time; + List LeapedWolves; + + PounceData(Player leader, WolfData wolfData, Vector direction) + { + Leader = leader; + WolfData = wolfData; + Target = leader.getLocation(); + Direction = direction.multiply(1.5); + Time = System.currentTimeMillis(); + LeapedWolves = new ArrayList<>(5); + } + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/HeroBiff.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/HeroBiff.java new file mode 100644 index 000000000..3ea9175bc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/HeroBiff.java @@ -0,0 +1,24 @@ +package nautilus.game.arcade.game.games.moba.kit.biff; + +import mineplex.core.common.skin.SkinData; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillSword; +import nautilus.game.arcade.kit.Perk; + +public class HeroBiff extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillSword(0), + new SkillLeash(1), + new SkillBiffDash(2), + new SkillWarHorse(3) + }; + + public HeroBiff(ArcadeManager manager) + { + super(manager, "Biff", PERKS, MobaRole.WARRIOR, SkinData.BIFF); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillBiffDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillBiffDash.java new file mode 100644 index 000000000..8db6b27f9 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillBiffDash.java @@ -0,0 +1,158 @@ +package nautilus.game.arcade.game.games.moba.kit.biff; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Effect; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class SkillBiffDash extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Dash into the air.", + "When you land any enemies near you are damaged", + "and thrown up into the air." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + private final Map _active = new HashMap<>(); + + public SkillBiffDash(int slot) + { + super("Battle Leap", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(11000); + setSneakActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @EventHandler + public void toggleSneak(PlayerToggleSneakEvent event) + { + if (!isSkillSneak(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @Override + public void useSkill(Player player) + { + if (_active.containsKey(player)) + { + return; + } + + super.useSkill(player); + + Vector direction = player.getLocation().getDirection().setY(1); + + UtilAction.velocity(player, direction); + + player.getWorld().playSound(player.getLocation(), Sound.IRONGOLEM_THROW, 1, 1F); + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, player.getLocation().add(0, 0.6, 0), 0.5F, 0.5F, 0.5F, 0.1F, 15, ViewDist.LONG); + + _active.put(player, System.currentTimeMillis()); + } + + @EventHandler + public void landed(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + Iterator iterator = _active.keySet().iterator(); + + while (iterator.hasNext()) + { + Player player = iterator.next(); + long start = _active.get(player); + + if (!player.isOnline()) + { + iterator.remove(); + } + + // They have just activated it + if (!UtilTime.elapsed(start, 1000) || player.getLocation().getBlock().getRelative(BlockFace.DOWN).getType() == Material.AIR) + { + continue; + } + + for (Block block : UtilBlock.getBlocksInRadius(player.getLocation(), 5)) + { + if (block.getType() == Material.AIR || block.getRelative(BlockFace.UP).getType() != Material.AIR || Math.random() > 0.5) + { + continue; + } + + block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType()); + } + + + for (LivingEntity entity : UtilEnt.getInRadius(player.getLocation(), 5).keySet()) + { + if (isTeamDamage(player, entity)) + { + continue; + } + + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, player.getLocation().add(0, 0.6, 0), 0.5F, 0.5F, 0.5F, 0.1F, 15, ViewDist.LONG); + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, 4, false, true, false, UtilEnt.getName(player), GetName()); + UtilAction.velocity(entity, new Vector(0, 0.6 + Math.random() / 2, 0)); + } + + iterator.remove(); + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + _active.remove(event.getEntity()); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillLeash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillLeash.java new file mode 100644 index 000000000..dcbb2ff1d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillLeash.java @@ -0,0 +1,129 @@ +package nautilus.game.arcade.game.games.moba.kit.biff; + +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.common.LeashedEntity; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class SkillLeash extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Enemy heroes near to Biff are hooked with a leash to you.", + "Leashed players are slowed and it breaks if the leashed player moves", + "too far away." + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.LEASH); + + private final Map> _leashed = new HashMap<>(); + + public SkillLeash(int slot) + { + super("Tether", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + setCooldown(12000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + Player player = event.getPlayer(); + + if (!isSkillItem(event) || _leashed.containsKey(player)) + { + return; + } + + List nearbyPlayers = UtilPlayer.getNearby(player.getLocation(), 8); + nearbyPlayers.removeIf(other -> isTeamDamage(other, player)); + + if (nearbyPlayers.isEmpty()) + { + player.sendMessage(F.main("Game", "There was no one in range to leash.")); + return; + } + + List leashedEntities = new ArrayList<>(nearbyPlayers.size()); + + StringBuilder builder = new StringBuilder(F.main("Game", "You leashed ")); + + for (Player nearby : nearbyPlayers) + { + nearby.setLeashHolder(player); + nearby.setPullWhileLeashed(false); + nearby.setShouldBreakLeash(false); + nearby.sendMessage(F.main("Game", F.name(player.getName()) + " leashed you.")); + nearby.playSound(nearby.getLocation(), Sound.DOOR_CLOSE, 1, 1); + builder.append(F.name(nearby.getName())).append(", "); + UtilAction.zeroVelocity(nearby); + Manager.GetCondition().Factory().Slow(GetName(), nearby, player, 5, 1, false, true, true, false); + leashedEntities.add(new LeashedEntity(Manager, nearby, player)); + } + + _leashed.put(player, leashedEntities); + + player.playSound(player.getLocation(), Sound.DOOR_CLOSE, 1, 1); + player.sendMessage(builder.toString()); + + useActiveSkill(() -> + { + for (LeashedEntity leashed : _leashed.remove(player)) + { + removeEffect(leashed); + } + + }, player, 5000); + } + + @EventHandler + public void updateLeashed(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (Entry> entry : _leashed.entrySet()) + { + Iterator iterator = entry.getValue().iterator(); + + while (iterator.hasNext()) + { + LeashedEntity leashed = iterator.next(); + + if (!UtilPlayer.isSpectator(entry.getKey()) && UtilMath.offsetSquared(entry.getKey(), leashed.getHost()) < 100) + { + continue; + } + + removeEffect(leashed); + iterator.remove(); + } + } + } + + private void removeEffect(LeashedEntity entity) + { + entity.getHost().removePotionEffect(PotionEffectType.SLOW); + entity.remove(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillWarHorse.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillWarHorse.java new file mode 100644 index 000000000..9a45a201d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/biff/SkillWarHorse.java @@ -0,0 +1,170 @@ +package nautilus.game.arcade.game.games.moba.kit.biff; + +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilTime; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.BuffManager; +import nautilus.game.arcade.game.games.moba.buff.buffs.BuffRooting; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Horse; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class SkillWarHorse extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Mounts you on a horse.", + "Any nearby enemy heroes are rooted and will be", + "unable to move." + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + private static final ItemStack HORSE_ARMOUR = new ItemStack(Material.IRON_BARDING); + private static final ItemStack SADDLE = new ItemStack(Material.SADDLE); + + private final Set _data = new HashSet<>(); + + public SkillWarHorse(int slot) + { + super("Cavalry Charge", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(45000); + setDropItemActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + for (WarHorseData data : _data) + { + if (data.Owner.equals(player)) + { + return; + } + } + + Manager.GetGame().CreatureAllowOverride = true; + + Horse horse = player.getWorld().spawn(player.getLocation(), Horse.class); + + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, horse.getLocation().add(0, 1, 0), 1, 1, 1, 0.1F, 50, ViewDist.LONG); + horse.getWorld().strikeLightningEffect(horse.getLocation()); + horse.getWorld().playSound(horse.getLocation(), Sound.HORSE_DEATH, 1, 1.1F); + horse.setHealth(20); + horse.setMaxHealth(horse.getHealth()); + horse.setJumpStrength(1); + horse.setMaxDomestication(1); + horse.setDomestication(horse.getMaxDomestication()); + horse.getInventory().setArmor(HORSE_ARMOUR); + horse.getInventory().setSaddle(SADDLE); + horse.setOwner(player); + horse.setPassenger(player); + MobaUtil.setTeamEntity(horse, Manager.GetGame().GetTeam(player)); + + Manager.GetGame().CreatureAllowOverride = false; + + _data.add(new WarHorseData(player, horse)); + + broadcast(player); + useActiveSkill(player, 5500); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + WarHorseData data = iterator.next(); + Player owner = data.Owner; + Horse horse = data.Horse; + + if (UtilTime.elapsed(data.Start, 6000) || UtilPlayer.isSpectator(owner) || horse.isDead() || !horse.isValid()) + { + horse.getWorld().playSound(horse.getLocation(), Sound.HORSE_BREATHE, 1, 1.1F); + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, horse.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5F, 0.1F, 50, ViewDist.LONG); + horse.remove(); + iterator.remove(); + } + else + { + Moba game = (Moba) Manager.GetGame(); + BuffManager buffManager = game.getBuffManager(); + + for (Player player : UtilPlayer.getNearby(horse.getLocation(), 5)) + { + if (isTeamDamage(owner, player) || !Recharge.Instance.use(player, GetName() + "Rooting", 2000, false, false)) + { + continue; + } + + owner.sendMessage(F.main("Game", "You hit " + F.name(player.getName()) + ".")); + Manager.GetDamage().NewDamageEvent(player, owner, null, DamageCause.CUSTOM, 10, false, true, false, UtilEnt.getName(owner), GetName()); + buffManager.apply(new BuffRooting(game, player, 1000)); + } + } + } + } + + @EventHandler + public void horseDamage(CustomDamageEvent event) + { + for (WarHorseData data : _data) + { + if (data.Horse.equals(event.GetDamageeEntity())) + { + event.SetCancelled("Biff Horse"); + return; + } + } + + } + + private class WarHorseData + { + public Player Owner; + public Horse Horse; + public long Start; + + WarHorseData(Player owner, Horse horse) + { + Owner = owner; + Horse = horse; + Start = System.currentTimeMillis(); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/HeroBob.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/HeroBob.java new file mode 100644 index 000000000..06ad4b260 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/HeroBob.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.kit.bob; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class HeroBob extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillPaint(0), + new SkillHappyTrees(1), + new SkillBeatTheDevil(2), + new SkillBuildPainting(3) + }; + + private static final ItemStack AMMO = new ItemBuilder(Material.SNOW_BALL) + .setTitle(C.cYellowB + "Titanium Hwhite") + .build(); + + public HeroBob(ArcadeManager manager) + { + super(manager, "Bob Ross", PERKS, MobaRole.MAGE, SkinData.BOB_ROSS); + + setAmmo(AMMO, 500); + setMaxAmmo(8); + setVisible(false); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBeatTheDevil.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBeatTheDevil.java new file mode 100644 index 000000000..55cc18082 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBeatTheDevil.java @@ -0,0 +1,47 @@ +package nautilus.game.arcade.game.games.moba.kit.bob; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Color; +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.inventory.ItemStack; + +public class SkillBeatTheDevil extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Bob Ross" + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillBeatTheDevil(int slot) + { + super("Beat The Devil Out Of It", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(12000); + + _collide = false; + _velocityTime = 800; + _velocityStopOnEnd = true; + } + + @Override + public void dashTick(Player player) + { + player.getWorld().playSound(player.getLocation(), player.getTicksLived() % 2 == 0 ? Sound.DOOR_OPEN : Sound.DOOR_CLOSE, 1, 0.5F); + + for (int i = 0; i < 10; i++) + { + UtilParticle.playColoredParticleToAll(Color.RED, ParticleType.RED_DUST, UtilAlg.getRandomLocation(player.getLocation().add(0, 1, 0), 2), 1, ViewDist.LONG); + } + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBuildPainting.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBuildPainting.java new file mode 100644 index 000000000..862caa9f5 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillBuildPainting.java @@ -0,0 +1,209 @@ +package nautilus.game.arcade.game.games.moba.kit.bob; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilMath; +import mineplex.core.projectile.IThrown; +import mineplex.core.projectile.ProjectileUser; +import mineplex.core.recharge.Recharge; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +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.Entity; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Set; + +public class SkillBuildPainting extends HeroSkill implements IThrown +{ + + private static final String[] DESCRIPTION = { + "Bob Ross" + }; + private static final BlockFace[] AXIS = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST }; + private static final byte[][] PAINTING = { + { + 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3 + }, + { + 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0, 3, 3, 3, 3 + }, + { + 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3 + }, + { + 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 13, 3 + }, + { + 3, 3, 0, 0, 0, 3, 3, 3, 5, 3, 3, 13, 3, 13, 3 + }, + { + 3, 3, 8, 8, 8, 8, 3, 5, 5, 5, 3, 13, 13, 13, 13 + }, + { + 3, 3, 8, 8, 8, 8, 3, 3, 12, 3, 13, 13, 13, 13, 13 + }, + { + 3, 3, 7, 7, 7, 7, 7, 3, 12, 3, 3, 12, 3, 12, 3 + }, + { + 5, 7, 7, 7, 7, 7, 7, 5, 12, 5, 5, 12, 5, 12, 5 + } + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + + public SkillBuildPainting(int slot) + { + super("The Joy Of Painting", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + if (!Recharge.Instance.use(player, GetName() + " Trigger", 5000, false, false)) + { + return; + } + + useActiveSkill(player, 4000); + broadcast(player); + + Set blocks = new HashSet<>(); + + Vector direction = player.getLocation().getDirection().normalize().setY(0); + Location start = player.getLocation().add(direction); + BlockFace facing = getFace(start.getYaw() + 180F); + Block center = start.getBlock().getRelative(facing).getRelative(BlockFace.UP); + + float leftYaw = start.getYaw() - 90; + BlockFace leftSide = getFace(leftYaw); + + for (int i = 0; i < 7; i++) + { + center = center.getRelative(leftSide); + } + + BlockFace rightSide = leftSide.getOppositeFace(); + + // Rows + for (int y = 0; y < PAINTING.length; y++) + { + byte[] row = PAINTING[y]; + + // Column in row + for (int x = 0; x < row.length; x++) + { + Block result = center; + + for (int i = 0; i < x; i++) + { + result = result.getRelative(rightSide); + } + + result = result.getRelative(0, 8, 0); + + for (int i = 0; i < y; i++) + { + result = result.getRelative(BlockFace.DOWN); + } + + Block fResult = result; + byte blockData = row[x]; + + Manager.runSyncLater(() -> + { + blocks.add(fResult); + Manager.GetBlockRestore().add(fResult, Material.WOOL.getId(), blockData, Long.MAX_VALUE); + + }, UtilMath.r(40)); + } + } + + Manager.runSyncLater(() -> + { + for (Block block : blocks) + { + if (Math.random() < 0.2) + { + FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation().add(0.5, 0.5, 0.5), block.getType(), block.getData()); + + fallingBlock.setVelocity(direction.clone().multiply(1 + (Math.random() * 0.4))); + Manager.GetProjectile().AddThrow(fallingBlock, player, this, 2000, true, true, true, false, 0.5F); + } + + Manager.GetBlockRestore().restore(block); + } + }, 80); + } + + @EventHandler + public void itemSpawn(ItemSpawnEvent event) + { + if (event.getEntity().getItemStack().getType() == Material.WOOL) + { + event.setCancelled(true); + } + } + + @Override + public void Collide(LivingEntity target, Block block, ProjectileUser data) + { + damage(data); + } + + @Override + public void Idle(ProjectileUser data) + { + + } + + @Override + public void Expire(ProjectileUser data) + { + damage(data); + } + + private void damage(ProjectileUser data) + { + Entity entity = data.getThrown(); + data.getThrown().getWorld().playEffect(entity.getLocation(), Effect.STEP_SOUND, Material.WOOL, (byte) 0); + + for (Entry entry : UtilEnt.getInRadius(entity.getLocation(), 3).entrySet()) + { + Manager.GetDamage().NewDamageEvent(entry.getKey(), data.getThrower(), null, DamageCause.BLOCK_EXPLOSION, 5, true, true, false, UtilEnt.getName(data.getThrower()), GetName()); + } + + data.getThrown().remove(); + } + + private BlockFace getFace(float yaw) + { + return AXIS[Math.round(yaw / 90F) & 0x3]; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillHappyTrees.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillHappyTrees.java new file mode 100644 index 000000000..9590d39f9 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillHappyTrees.java @@ -0,0 +1,176 @@ +package nautilus.game.arcade.game.games.moba.kit.bob; + +import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilEvent.ActionType; +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 nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaParticles; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.*; +import java.util.Map.Entry; + +public class SkillHappyTrees extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Bob Ross" + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.SAPLING); + + private final Set _data = new HashSet<>(); + + public SkillHappyTrees(int slot) + { + super("Happy Little Trees", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(15000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + _data.add(new HappyTreeData(player)); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + HappyTreeData data = iterator.next(); + + if (UtilTime.elapsed(data.Start, 9000)) + { + iterator.remove(); + } + else if (data.Tree1 == null) + { + data.Tree1 = buildTree(data.Center); + } + else if (data.Tree2 == null) + { + data.Tree2 = buildTree(data.Center); + } + + if (UtilTime.elapsed(data.Start, 2000)) + { + healPlayers(data.Owner, data.Tree1); + healPlayers(data.Owner, data.Tree2); + } + } + } + + private Block buildTree(Location center) + { + Location start = UtilAlg.getRandomLocation(center, 5, 0, 5); + Map blocks = getTree(start); + + for (Entry entry : blocks.entrySet()) + { + Manager.runSyncLater(() -> Manager.GetBlockRestore().add(entry.getKey(), entry.getValue().getId(), (byte) 0, (long) (6000 + (Math.random() * 1000))), UtilMath.r(60)); + } + + return start.getBlock(); + } + + private Map getTree(Location start) + { + Block last = start.getBlock().getRelative(BlockFace.DOWN); + Map blocks = new HashMap<>(); + + // Trunk + for (int i = 0; i < 5; i++) + { + Block next = last.getRelative(BlockFace.UP); + last = next; + blocks.put(next, Material.LOG); + } + + last = last.getRelative(BlockFace.DOWN).getRelative(BlockFace.DOWN); + + // Bottom Leaves + for (Block block : UtilBlock.getInBoundingBox(last.getLocation().add(2, 1, 2), last.getLocation().subtract(2, 0, 2), false)) + { + blocks.put(block, Material.LEAVES); + } + + last = last.getRelative(BlockFace.UP).getRelative(BlockFace.UP); + + // Middle Leaves + for (Block block : UtilBlock.getInBoundingBox(last.getLocation().add(1, 0, 1), last.getLocation().subtract(1, 0, 1), false)) + { + blocks.put(block, Material.LEAVES); + } + + last = last.getRelative(BlockFace.UP); + + // Top Leaves + blocks.put(last.getRelative(BlockFace.NORTH), Material.LEAVES); + blocks.put(last.getRelative(BlockFace.WEST), Material.LEAVES); + blocks.put(last.getRelative(BlockFace.EAST), Material.LEAVES); + blocks.put(last.getRelative(BlockFace.SOUTH), Material.LEAVES); + blocks.put(last.getRelative(BlockFace.UP), Material.LEAVES); + + return blocks; + } + + private void healPlayers(Player owner, Block block) + { + for (LivingEntity entity : UtilEnt.getInRadius(block.getLocation(), 5).keySet()) + { + // Don't heal enemies + if (!isTeamDamage(entity, owner)) + { + continue; + } + + MobaUtil.heal(entity, owner, 2); + MobaParticles.healing(entity, 1); + } + } + + private class HappyTreeData + { + public Player Owner; + public long Start; + public Location Center; + public Block Tree1; + public Block Tree2; + + public HappyTreeData(Player owner) + { + Owner = owner; + Start = System.currentTimeMillis(); + Center = owner.getLocation(); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillPaint.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillPaint.java new file mode 100644 index 000000000..b5f8386bf --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/bob/SkillPaint.java @@ -0,0 +1,103 @@ +package nautilus.game.arcade.game.games.moba.kit.bob; + +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilMath; +import mineplex.core.projectile.IThrown; +import mineplex.core.projectile.ProjectileUser; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.Random; + +public class SkillPaint extends HeroSkill implements IThrown +{ + + private static final String[] DESCRIPTION = { + "Bob Ross" + }; + private static final byte[] COLOURS = { 14, 1, 4, 5, 3, 11, 0}; + private static final int DAMAGE = 2; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.DIAMOND_BARDING); + + public SkillPaint(int slot) + { + super("1-Inch Brush", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + if (!_kit.useAmmo(player, 1)) + { + return; + } + + useSkill(player); + + Snowball snowball = player.launchProjectile(Snowball.class); + + ((Moba) Manager.GetGame()).getTowerManager().addProjectile(player, snowball, DAMAGE); + Manager.GetProjectile().AddThrow(snowball, player, this, -1, true, true, true, false, 0.5F); + } + + @Override + public void Collide(LivingEntity target, Block block, ProjectileUser data) + { + Player thrower = (Player) data.getThrower(); + Random random = UtilMath.random; + + if (target != null) + { + thrower.playSound(thrower.getLocation(), Sound.LAVA_POP, 1, 1.3F); + Manager.GetDamage().NewDamageEvent(target, thrower, (Projectile) data.getThrown(), DamageCause.PROJECTILE, DAMAGE, true, true, false, UtilEnt.getName(thrower), GetName()); + } + + for (Block nearby : UtilBlock.getBlocksInRadius(data.getThrown().getLocation(), 2)) + { + if (UtilBlock.airFoliage(nearby)) + { + continue; + } + + Manager.GetBlockRestore().add(nearby, Material.STAINED_CLAY.getId(), COLOURS[random.nextInt(COLOURS.length)], (long) (3000 + (Math.random() * 500))); + } + + for (LivingEntity entity : UtilEnt.getInRadius(data.getThrown().getLocation(), 2).keySet()) + { + Manager.GetDamage().NewDamageEvent(entity, thrower, (Projectile) data.getThrown(), DamageCause.PROJECTILE, 2, true, true, false, UtilEnt.getName(thrower), GetName()); + } + } + + @Override + public void Idle(ProjectileUser data) + { + + } + + @Override + public void Expire(ProjectileUser data) + { + + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/DashSkill.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/DashSkill.java new file mode 100644 index 000000000..7d8899320 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/DashSkill.java @@ -0,0 +1,224 @@ +package nautilus.game.arcade.game.games.moba.kit.common; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.particles.effects.LineParticle; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.*; +import java.util.Map.Entry; + +public class DashSkill extends HeroSkill +{ + + // Teleport Only + protected boolean _teleport = false; + protected boolean _horizontial = false; + protected double _range = 10; + protected ParticleType _particleType = ParticleType.FIREWORKS_SPARK; + + // Velocity + protected long _velocityTime; + protected double _velocityMagnitude = 1; + protected boolean _velocityStopOnEnd = false; + + // Collisions + protected boolean _collide = true; + protected double _collideRange = 2; + protected boolean _collideTeammates = false; + protected boolean _collidePlayers = true; + protected boolean _collideEntities = true; + protected boolean _collideOnce = true; + + private final Map _startTime; + + public DashSkill(String name, String[] perkDesc, ItemStack itemStack, int slot) + { + super(name, perkDesc, itemStack, slot, ActionType.ANY); + + _startTime = new HashMap<>(); + setSneakActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @EventHandler + public void toggleSneak(PlayerToggleSneakEvent event) + { + if (!isSkillSneak(event)) + { + return; + } + + Player player = event.getPlayer(); + + useSkill(player); + } + + @Override + public void useSkill(Player player) + { + super.useSkill(player); + + preDash(player); + + if (_teleport) + { + Vector direction = player.getLocation().getDirection(); + + if (_horizontial) + { + direction.setY(0); + } + + LineParticle particle = new LineParticle(player.getEyeLocation(), direction, 0.8, _range, null, _particleType, UtilServer.getPlayers()); + + while (!particle.update()) + { + dashTick(player); + checkCollisions(player, particle.getLastLocation()); + } + + player.teleport(particle.getDestination()); + postDash(player); + } + // Otherwise we set their velocity. + else if (_velocityTime > 0) + { + _startTime.put(player, System.currentTimeMillis()); + } + else + { + setVelocity(player); + } + } + + @EventHandler + public void updateVelocity(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + for (Entry entry : _startTime.entrySet()) + { + Player player = entry.getKey(); + long start = entry.getValue(); + + if (UtilTime.elapsed(start, _velocityTime)) + { + if (_velocityStopOnEnd) + { + UtilAction.zeroVelocity(player); + } + _startTime.remove(player); + postDash(player); + } + else + { + checkCollisions(player, player.getLocation()); + setVelocity(player); + } + } + } + + private void setVelocity(Player player) + { + Vector direction = player.getLocation().getDirection().multiply(_velocityMagnitude); + + if (_horizontial) + { + direction.setY(0); + } + + dashTick(player); + UtilAction.velocity(player, direction); + } + + private void checkCollisions(Player player, Location location) + { + // No colliding + if (!_collide || !_collideEntities && !_collidePlayers) + { + return; + } + + // All Living entities within the range + for (Entry entry : UtilEnt.getInRadius(location, _collideRange).entrySet()) + { + LivingEntity entity = entry.getKey(); + double scale = entry.getValue(); + + // If player hit themselves + if (player.equals(entity)) + { + continue; + } + + if (_collideOnce && !Recharge.Instance.use(player, GetName() + entity.getUniqueId(), 500, false, false)) + { + continue; + } + + // If not allowing collisions with players + if (!_collidePlayers) + { + continue; + } + + boolean sameTeam = isTeamDamage(entity, player); + + // If their teams are the same and we don't allow collisions with teammates, ignore + if (sameTeam && !_collideTeammates) + { + continue; + } + + collideEntity(entity, player, scale, sameTeam); + } + } + + public void preDash(Player player) + { + } + + public void dashTick(Player player) + { + } + + public void collideEntity(LivingEntity entity, Player damager, double scale, boolean sameTeam) + { + } + + public void postDash(Player player) + { + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/LeashedEntity.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/LeashedEntity.java new file mode 100644 index 000000000..b0100b73d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/LeashedEntity.java @@ -0,0 +1,85 @@ +package nautilus.game.arcade.game.games.moba.kit.common; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilServer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.ArcadeManager; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class LeashedEntity implements Listener +{ + + private final LivingEntity _host; + private final Zombie _fakeLeash; + + public LeashedEntity(ArcadeManager manager, LivingEntity host, LivingEntity leasher) + { + manager.GetGame().CreatureAllowOverride = true; + + _host = host; + _fakeLeash = host.getWorld().spawn(host.getLocation(), Zombie.class); + UtilEnt.vegetate(_fakeLeash); + UtilEnt.silence(_fakeLeash, true); + _fakeLeash.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + _fakeLeash.setLeashHolder(leasher); + + manager.GetGame().CreatureAllowOverride = false; + + UtilServer.RegisterEvents(this); + } + + public void remove() + { + _fakeLeash.setLeashHolder(null); + _fakeLeash.remove(); + UtilServer.Unregister(this); + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Location location = _host.getLocation(); + ((CraftLivingEntity) _fakeLeash).getHandle().setPosition(location.getX(), location.getY(), location.getZ()); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void fakeLeashDamage(CustomDamageEvent event) + { + if (event.GetDamageeEntity().equals(_fakeLeash) && event.GetCause() == DamageCause.ENTITY_ATTACK) + { + event.setDamagee(_host); + event.SetIgnoreRate(false); + } + } + + @EventHandler + public void fakeLeashFire(EntityCombustEvent event) + { + if (event.getEntity().equals(_fakeLeash)) + { + event.setCancelled(true); + } + } + + public LivingEntity getHost() + { + return _host; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillBow.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillBow.java new file mode 100644 index 000000000..2d2a105a1 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillBow.java @@ -0,0 +1,48 @@ +package nautilus.game.arcade.game.games.moba.kit.common; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class SkillBow extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Please work" + }; + + private static final ItemStack SKILL_ITEM = new ItemBuilder(Material.BOW) + .setTitle(C.cGreenB + "Bow") + .setUnbreakable(true) + .build(); + + public SkillBow(int slot) + { + super("Bow", DESCRIPTION, SKILL_ITEM, slot, null); + } + + @Override + public void giveItem(Player player) + { + Moba host = (Moba) Manager.GetGame(); + List ownedItems = host.getShop().getOwnedItems(player); + + for (MobaItem item : ownedItems) + { + if (item.getItem().getType() == Material.BOW) + { + player.getInventory().setItem(getSlot(), item.getItem()); + return; + } + } + + player.getInventory().setItem(getSlot(), SKILL_ITEM); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillSword.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillSword.java new file mode 100644 index 000000000..c7834d07d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/common/SkillSword.java @@ -0,0 +1,46 @@ +package nautilus.game.arcade.game.games.moba.kit.common; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilItem; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class SkillSword extends HeroSkill +{ + + private static final ItemStack SKILL_ITEM = new ItemBuilder(Material.WOOD_SWORD) + .setTitle(C.cGreenB + "Sword") + .setUnbreakable(true) + .build(); + + public SkillSword(int slot) + { + super("Sword", new String[0], SKILL_ITEM, slot, null); + } + + @Override + public void giveItem(Player player) + { + Moba host = (Moba) Manager.GetGame(); + List ownedItems = host.getShop().getOwnedItems(player); + + for (MobaItem item : ownedItems) + { + if (UtilItem.isSword(item.getItem())) + { + player.getInventory().setItem(getSlot(), item.getItem()); + return; + } + } + + player.getInventory().setItem(getSlot(), SKILL_ITEM); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/HeroDana.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/HeroDana.java new file mode 100644 index 000000000..f305be717 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/HeroDana.java @@ -0,0 +1,24 @@ +package nautilus.game.arcade.game.games.moba.kit.dana; + +import mineplex.core.common.skin.SkinData; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillSword; +import nautilus.game.arcade.kit.Perk; + +public class HeroDana extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillSword(0), + new SkillPulseHeal(1), + new SkillDanaDash(2), + new SkillRally(3), + }; + + public HeroDana(ArcadeManager manager) + { + super(manager, "Dana", PERKS, MobaRole.WARRIOR, SkinData.DANA); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillDanaDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillDanaDash.java new file mode 100644 index 000000000..8fcb89839 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillDanaDash.java @@ -0,0 +1,83 @@ +package nautilus.game.arcade.game.games.moba.kit.dana; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilEnt; +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 nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.Random; + +public class SkillDanaDash extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Dash along the ground.", + "Nearby enemies are thrown up into the air." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillDanaDash(int slot) + { + super("Knock up", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(10000); + + _velocityTime = 600; + _horizontial = true; + _velocityStopOnEnd = true; + } + + @Override + public void preDash(Player player) + { + player.getWorld().playSound(player.getLocation(), Sound.BLAZE_HIT, 2, 0.4F); + } + + @Override + public void dashTick(Player player) + { + Random random = UtilMath.random; + Location location = player.getLocation().add(random.nextInt(5) - 2.5, random.nextInt(3), random.nextInt(5) - 2.5); + UtilParticle.PlayParticle(ParticleType.CLOUD, location.add(0, 1, 0), 0.5F, 0.5F, 0.5f, 0.1F, 10, ViewDist.LONG); + } + + @Override + public void collideEntity(LivingEntity entity, Player damager, double scale, boolean sameTeam) + { + double damage; + + if (entity instanceof Player) + { + damage = 10; + UtilAction.velocity(entity, new Vector(Math.random() / 2 - 0.25, 1, Math.random() / 2 - 0.25)); + } + else + { + damage = 6; + UtilAction.velocity(entity, new Vector(Math.random() - 0.5, 0.5, Math.random() - 0.5)); + } + + entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_HIT, 1, 0.5F); + Manager.GetDamage().NewDamageEvent(entity, damager, null, DamageCause.CUSTOM, damage, false, true, false, UtilEnt.getName(damager), GetName()); + } + + @Override + public void postDash(Player player) + { + player.getWorld().playSound(player.getLocation(), Sound.EXPLODE, 2, 0.4F); + UtilParticle.PlayParticle(ParticleType.LARGE_EXPLODE, player.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5f, 0.1F, 3, ViewDist.LONG); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillPulseHeal.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillPulseHeal.java new file mode 100644 index 000000000..6d26e4cc3 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillPulseHeal.java @@ -0,0 +1,94 @@ +package nautilus.game.arcade.game.games.moba.kit.dana; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +public class SkillPulseHeal extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Heals nearby allies and minions." + }; + + private static final ItemStack SKILL_ITEM = new ItemBuilder(Material.INK_SACK, (byte) 10).build(); + + public SkillPulseHeal(int slot) + { + super("Pulse Heal", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + setCooldown(8000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + useSkill(player); + + for (LivingEntity entity : UtilEnt.getInRadius(player.getLocation(), 5).keySet()) + { + // Don't heal enemies + if (!isTeamDamage(entity, player)) + { + continue; + } + + MobaUtil.heal(entity, player, 4); + } + + displayPulse(player.getLocation().add(0, 0.5, 0)); + } + + private void displayPulse(Location location) + { + Manager.runSyncTimer(new BukkitRunnable() + { + + double theta = 0; + double radius = 0; + + @Override + public void run() + { + if (radius > 5) + { + cancel(); + return; + } + + for (double theta2 = 0; theta2 < 2 * Math.PI; theta2 += Math.PI / 3) + { + double x = radius * Math.sin(theta + theta2); + double z = radius * Math.cos(theta + theta2); + + location.add(x, 0.5, z); + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, location, 0, 0, 0, 0.1F, 1, ViewDist.LONG); + + location.subtract(x, 0.5, z); + } + + theta += Math.PI / 100; + radius += 0.2; + } + }, 0, 1); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillRally.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillRally.java new file mode 100644 index 000000000..ec5ac4cc9 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/dana/SkillRally.java @@ -0,0 +1,242 @@ +package nautilus.game.arcade.game.games.moba.kit.dana; + +import mineplex.core.common.events.EntityVelocityChangeEvent; +import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilEvent.ActionType; +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 nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaParticles; +import org.bukkit.*; +import org.bukkit.block.Banner; +import org.bukkit.block.Block; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class SkillRally extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "You leap up into the air, and upon landing", + "you plant a banner that heals nearby allies", + "and minions." + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + + private Set _data = new HashSet<>(); + + public SkillRally(int slot) + { + super("Rally", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(40000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + Vector vector = player.getLocation().getDirection(); + + for (RallyData data : _data) + { + if (data.Owner.equals(player)) + { + return; + } + } + + vector.setY(1.5); + + UtilAction.velocity(player, vector); + _data.add(new RallyData(player)); + broadcast(player); + } + + @EventHandler + public void updateLand(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + RallyData data = iterator.next(); + Player player = data.Owner; + + if (data.Landed) + { + if (UtilTime.elapsed(data.LandTime, 7000)) + { + iterator.remove(); + } + else + { + for (Player nearby : UtilPlayer.getNearby(data.Banner, 5)) + { + // Only heal allies + if (!isTeamDamage(nearby, player)) + { + continue; + } + + if (Math.random() > 0.75) + { + MobaParticles.healing(nearby, 1); + } + Manager.GetCondition().Factory().Regen(GetName(), nearby, data.Owner, 3, 1, false, true, false); + } + } + } + else if (UtilTime.elapsed(data.LaunchTime, 1000) && UtilEnt.isGrounded(data.Owner)) + { + data.LandTime = System.currentTimeMillis(); + data.Landed = true; + Location location = data.Owner.getLocation(); + data.Banner = location; + + useActiveSkill(player, 7000); + + GameTeam team = Manager.GetGame().GetTeam(player); + Block block = location.getBlock(); + + Manager.GetBlockRestore().add(block, Material.STANDING_BANNER.getId(), (byte) 0, 7500); + + Banner banner = (Banner) block.getState(); + banner.setBaseColor(team.GetColor() == ChatColor.RED ? DyeColor.RED : DyeColor.BLUE); + banner.addPattern(getPattern(team)); + banner.update(); + + for (Block nearby : UtilBlock.getBlocksInRadius(banner.getLocation(), 5)) + { + if (UtilBlock.airFoliage(nearby)) + { + continue; + } + + Manager.GetBlockRestore().add(nearby, Material.STAINED_CLAY.getId(), team.GetColorData(), (long) (7000 + (Math.random() * 500))); + if (Math.random() > 0.9) + { + nearby.getWorld().playEffect(nearby.getLocation(), Effect.STEP_SOUND, Material.STAINED_CLAY, team.GetColorData()); + } + } + + for (LivingEntity nearby : UtilEnt.getInRadius(player.getLocation(), 3).keySet()) + { + Manager.GetDamage().NewDamageEvent(nearby, player, null, DamageCause.CUSTOM, 5, true, true, false, UtilEnt.getName(player), GetName()); + } + } + } + } + + @EventHandler + public void updateParticles(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + for (RallyData data : _data) + { + if (!data.Landed) + { + continue; + } + + Location banner = data.Banner; + + for (int i = 0; i < 5; i++) + { + double x = 5 * Math.sin(data.ParticleTheta); + double z = 5 * Math.cos(data.ParticleTheta); + + banner.add(x, 0.25, z); + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, banner, 0, 0, 0, 0.1F, 1, ViewDist.LONG); + + banner.subtract(x, 0.25, z); + + data.ParticleTheta += Math.PI / 100; + } + } + } + + @EventHandler + public void velocityChange(EntityVelocityChangeEvent event) + { + for (RallyData data : _data) + { + if (!data.Landed && data.Owner.equals(event.getEntity())) + { + event.setCancelled(true); + } + } + } + + @EventHandler + public void itemSpawn(ItemSpawnEvent event) + { + if (event.getEntity().getItemStack().getType() == Material.BANNER) + { + event.setCancelled(true); + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + _data.removeIf(rallyData -> rallyData.Owner.equals(event.getEntity())); + } + + private Pattern getPattern(GameTeam team) + { + return team.GetColor() == ChatColor.RED ? new Pattern(DyeColor.WHITE, PatternType.CROSS) : new Pattern(DyeColor.WHITE, PatternType.CIRCLE_MIDDLE); + } + + private class RallyData + { + + Player Owner; + Location Banner; + boolean Landed; + long LaunchTime; + long LandTime; + double ParticleTheta; + + RallyData(Player owner) + { + Owner = owner; + LaunchTime = System.currentTimeMillis(); + } + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/HeroDevon.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/HeroDevon.java new file mode 100644 index 000000000..7ff52d150 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/HeroDevon.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.kit.devon; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillBow; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class HeroDevon extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillBow(0), + new SkillTNTArrows(1), + new SkillBoost(2), + new SkillInfinity(3) + }; + + private static final ItemStack AMMO = new ItemBuilder(Material.ARROW) + .setTitle(C.cYellowB + "Hunting Arrow") + .setUnbreakable(true) + .build(); + + public HeroDevon(ArcadeManager manager) + { + super(manager, "Devon", PERKS, MobaRole.HUNTER, SkinData.DEVON); + + setAmmo(AMMO, 3000); + setMaxAmmo(3); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillBoost.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillBoost.java new file mode 100644 index 000000000..eda785059 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillBoost.java @@ -0,0 +1,65 @@ +package nautilus.game.arcade.game.games.moba.kit.devon; + +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.minecraft.game.core.condition.ConditionFactory; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; + +public class SkillBoost extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Gain Speed II and Jump Boost I for 3 seconds.", + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillBoost(int slot) + { + super("Hunters Boost", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(10000); + setSneakActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + useSkill(player); + } + + @EventHandler + public void toggleSneak(PlayerToggleSneakEvent event) + { + if (!isSkillSneak(event)) + { + return; + } + + Player player = event.getPlayer(); + useSkill(player); + } + + @Override + public void useSkill(Player player) + { + super.useSkill(player); + + ConditionFactory factory = Manager.GetCondition().Factory(); + int time = 3; + + factory.Speed(GetName(), player, null, time, 1, true, true, false); + factory.Jump(GetName(), player, null, time, 0, true, true, false); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillInfinity.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillInfinity.java new file mode 100644 index 000000000..6097e9a28 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillInfinity.java @@ -0,0 +1,143 @@ +package nautilus.game.arcade.game.games.moba.kit.devon; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class SkillInfinity extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "For 7 seconds, your arrow shots don't consume arrows.", + "They also become heat-seeking and inflict wither onto players." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + + private final Map _arrows = new HashMap<>(); + private final Set _active = new HashSet<>(); + + public SkillInfinity(int slot) + { + super("Infinity", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event) || _active.contains(event.getPlayer())) + { + return; + } + + Player player = event.getPlayer(); + ItemStack bow = player.getInventory().getItem(0); + + if (bow == null || bow.getType() != Material.BOW) + { + return; + } + + // Give 1 arrow just incase the player didn't have one + _kit.giveAmmo(player, 1); + bow.addEnchantment(Enchantment.ARROW_INFINITE, 1); + _active.add(player); + + broadcast(player); + useActiveSkill(() -> + { + bow.removeEnchantment(Enchantment.ARROW_INFINITE); + _active.remove(player); + }, player, 7000); + } + + @EventHandler + public void shootArrow(EntityShootBowEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + if (!hasPerk(player) || !_active.contains(player)) + { + return; + } + + Moba moba = (Moba) Manager.GetGame(); + + moba.getArrowKbManager().allowKnockback(event.getProjectile()); + _arrows.put(event.getProjectile(), player); + } + + @EventHandler + public void updateArrowTarget(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + for (Entry entry : _arrows.entrySet()) + { + Entity entity = entry.getKey(); + Player player = entry.getValue(); + GameTeam team = Manager.GetGame().GetTeam(player); + + for (Player nearby : UtilPlayer.getInRadius(entity.getLocation(), 6).keySet()) + { + // If the target is on the same team + if (UtilPlayer.isSpectator(player) || team.equals(Manager.GetGame().GetTeam(nearby))) + { + continue; + } + + UtilAction.velocity(entity, UtilAlg.getTrajectory(entity.getLocation(), nearby.getLocation().add(0, 1.5, 0))); + } + } + } + + @EventHandler + public void arrowDamage(CustomDamageEvent event) + { + if (_arrows.containsKey(event.GetProjectile())) + { + Manager.GetCondition().Factory().Wither(GetName(), event.GetDamageeEntity(), event.GetDamagerEntity(true), 3, 0, false, true, false); + } + } + + @EventHandler + public void projectileHit(ProjectileHitEvent event) + { + // Delay this as the when the CustomDamageEvent is run. The arrow is already removed from the map. + Manager.runSyncLater(() -> _arrows.remove(event.getEntity()), 1); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillTNTArrows.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillTNTArrows.java new file mode 100644 index 000000000..b871b1e7c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/devon/SkillTNTArrows.java @@ -0,0 +1,154 @@ +package nautilus.game.arcade.game.games.moba.kit.devon; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class SkillTNTArrows extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Your next 3 arrows are infused with TNT.", + "They explode on contact dealing damage and knockback." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.TNT); + + private final Map _playerArrows = new HashMap<>(); + private final Set _arrows = new HashSet<>(); + + public SkillTNTArrows(int slot) + { + super("TNT Infusion", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(17000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + _playerArrows.put(player, 3); + UtilInv.addDullEnchantment(player.getItemInHand()); + player.getItemInHand().setAmount(3); + } + + @EventHandler + public void shootArrow(EntityShootBowEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + if (!hasPerk(player) || !_playerArrows.containsKey(player)) + { + return; + } + + ItemStack itemStack = player.getInventory().getItem(getSlot()); + int arrows = _playerArrows.get(player); + + if (arrows == 1) + { + _playerArrows.remove(player); + useSkill(player); + } + else + { + arrows--; + _playerArrows.put(player, arrows); + itemStack.setAmount(arrows); + } + + Moba moba = (Moba) Manager.GetGame(); + + moba.getArrowKbManager().allowKnockback(event.getProjectile()); + _arrows.add((Arrow) event.getProjectile()); + } + + @EventHandler + public void projectileHit(ProjectileHitEvent event) + { + ProjectileSource source = event.getEntity().getShooter(); + + if (!(source instanceof Player)) + { + return; + } + + Player player = (Player) source; + Projectile projectile = event.getEntity(); + + if (!_arrows.contains(projectile)) + { + return; + } + + _arrows.remove(projectile); + + Location location = projectile.getLocation(); + + location.getWorld().playSound(location, Sound.EXPLODE, 1, 0.9F); + UtilParticle.PlayParticle(ParticleType.HUGE_EXPLOSION, location, 0, 0, 0, 0.1F, 1, ViewDist.LONG); + double damage = MobaUtil.scaleDamageWithBow(player.getInventory().getItem(0),5); + + for (Entry entry : UtilEnt.getInRadius(location, 5).entrySet()) + { + if (entry.getKey().equals(player)) + { + continue; + } + + Manager.GetDamage().NewDamageEvent(entry.getKey(), player, null, DamageCause.CUSTOM, entry.getValue() * damage, true, true, false, UtilEnt.getName(player), GetName()); + } + } + + @EventHandler + public void playerDeath(CombatDeathEvent event) + { + _playerArrows.remove(event.GetEvent().getEntity()); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _playerArrows.remove(event.getPlayer()); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/HeroHattori.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/HeroHattori.java new file mode 100644 index 000000000..e9438b9c1 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/HeroHattori.java @@ -0,0 +1,26 @@ +package nautilus.game.arcade.game.games.moba.kit.hattori; + +import mineplex.core.common.skin.SkinData; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillSword; +import nautilus.game.arcade.kit.Perk; +import nautilus.game.arcade.kit.perks.PerkDoubleJump; + +public class HeroHattori extends HeroKit +{ + + private static final Perk[] PERKS = { + new PerkDoubleJump("Double Jump", 1, 1, true, 3000, true), + new SkillSword(0), + new SkillSnowball(1), + new SkillNinjaDash(2), + new SkillNinjaBlade(3) + }; + + public HeroHattori(ArcadeManager manager) + { + super(manager, "Hattori", PERKS, MobaRole.ASSASSIN, SkinData.HATTORI); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaBlade.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaBlade.java new file mode 100644 index 000000000..d0f8bf1f4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaBlade.java @@ -0,0 +1,148 @@ +package nautilus.game.arcade.game.games.moba.kit.hattori; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilItem; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.common.SkillSword; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class SkillNinjaBlade extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Turns into a Diamond Sword that deals extreme", + "damage to any player hit by it." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + private static final ItemStack ACTIVE_ITEM = new ItemBuilder(Material.DIAMOND_SWORD) + .setTitle(C.cGreenB + "ENDER BLADE") + .setUnbreakable(true) + .build(); + private static final int ACTIVE_SLOT = 0; + private static final int BASE_DAMAGE_INCREASE = 4; + + private Map _active = new HashMap<>(); + + public SkillNinjaBlade(int slot) + { + super("Ender Blade", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event) || _active.containsKey(event.getPlayer().getUniqueId())) + { + return; + } + + Player player = event.getPlayer(); + PlayerInventory inventory = player.getInventory(); + + inventory.setItem(ACTIVE_SLOT, ACTIVE_ITEM); + inventory.setHeldItemSlot(ACTIVE_SLOT); + + int damage = BASE_DAMAGE_INCREASE; + ItemStack sword = inventory.getItem(ACTIVE_SLOT); + + if (sword == null) + { + return; + } + + Material material = sword.getType(); + + // Increase damage based on the sword they had previously + switch (material) + { + case WOOD_SWORD: + damage += 2; + break; + case STONE_SWORD: + damage += 3; + break; + case GOLD_SWORD: + case IRON_SWORD: + damage += 4; + break; + case DIAMOND_SWORD: + damage += 5; + break; + } + + _active.put(player.getUniqueId(), damage); + + int i = 0; + for (ItemStack itemStack : inventory.getContents()) + { + if (itemStack != null && !itemStack.equals(ACTIVE_ITEM) && UtilItem.isSword(itemStack)) + { + inventory.setItem(i, null); + } + + i++; + } + + broadcast(player); + useActiveSkill(() -> + { + _active.remove(player.getUniqueId()); + + for (Perk perk : Kit.GetPerks()) + { + if (perk instanceof SkillSword) + { + ((SkillSword) perk).giveItem(player); + } + } + + }, player, 7000); + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + Entity entity = event.GetDamageeEntity(); + Player player = event.GetDamagerPlayer(false); + Player damageePlayer = event.GetDamageePlayer(); + + if (player == null || damageePlayer == null || isTeamDamage(damageePlayer, player)) + { + return; + } + + ItemStack itemStack = player.getItemInHand(); + + if (!_active.containsKey(player.getUniqueId()) || itemStack == null || itemStack.getType() != Material.DIAMOND_SWORD || itemStack.getItemMeta() == null || !itemStack.getItemMeta().getDisplayName().equals(ACTIVE_ITEM.getItemMeta().getDisplayName())) + { + return; + } + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, entity.getLocation().add(0, 1, 0), 1F, 1F, 1F, 0.1F, 50, ViewDist.LONG); + entity.getWorld().playSound(entity.getLocation(), Sound.EXPLODE, 2, 0.5F); + event.AddMod(GetName(), _active.get(player.getUniqueId())); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaDash.java new file mode 100644 index 000000000..0b886a430 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillNinjaDash.java @@ -0,0 +1,72 @@ +package nautilus.game.arcade.game.games.moba.kit.hattori; + +import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.particles.effects.LineParticle; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Bukkit; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class SkillNinjaDash extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Dash forward dealing damage to any enemy", + "you collide with." + }; + + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillNinjaDash(int slot) + { + super("Ninja Dash", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(7000); + + _teleport = true; + _range = 10; + } + + @Override + public void preDash(Player player) + { + playFirework(player); + } + + @Override + public void collideEntity(LivingEntity entity, Player player, double scale, boolean sameTeam) + { + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, 8, true, true, false, UtilEnt.getName(player), GetName()); + } + + @Override + public void postDash(Player player) + { + playFirework(player); + } + + private void playFirework(Player player) + { + GameTeam team = Manager.GetGame().GetTeam(player); + FireworkEffect effect = FireworkEffect.builder().with(Type.BALL).withColor(team.GetColorBase()).withFlicker().build(); + UtilFirework.playFirework(player.getLocation(), effect); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillSnowball.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillSnowball.java new file mode 100644 index 000000000..f1d06a1dc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hattori/SkillSnowball.java @@ -0,0 +1,95 @@ +package nautilus.game.arcade.game.games.moba.kit.hattori; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.projectile.IThrown; +import mineplex.core.projectile.ProjectileUser; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Snowball; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +public class SkillSnowball extends HeroSkill implements IThrown +{ + + private static final String[] DESCRIPTION = { + "Fires 3 snowballs, one after another.", + "Each snowball deals damage to any enemy it hits." + }; + private static final int DAMAGE = 3; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.SNOW_BALL); + + public SkillSnowball(int slot) + { + super("Shuriken", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(1000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + event.setCancelled(true); + + Player player = event.getPlayer(); + + useSkill(player); + + Manager.runSyncTimer(new BukkitRunnable() + { + int balls = 0; + + @Override + public void run() + { + Snowball snowball = player.launchProjectile(Snowball.class); + + ((Moba) Manager.GetGame()).getTowerManager().addProjectile(player, snowball, DAMAGE); + Manager.GetProjectile().AddThrow(snowball, player, SkillSnowball.this, -1, true, true, true, false, 0.5F); + + if (++balls == 3) + { + cancel(); + } + } + }, 0, 4); + } + + @Override + public void Collide(LivingEntity target, Block block, ProjectileUser data) + { + Player thrower = (Player) data.getThrower(); + + if (target != null && !isTeamDamage(target, thrower)) + { + thrower.playSound(thrower.getLocation(), Sound.LAVA_POP, 1, 1.3F); + Manager.GetDamage().NewDamageEvent(target, thrower, (Projectile) data.getThrown(), DamageCause.CUSTOM, DAMAGE, false, true, false, UtilEnt.getName(thrower), GetName()); + } + } + + @Override + public void Idle(ProjectileUser data) + { + } + + @Override + public void Expire(ProjectileUser data) + { + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/HPManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/HPManager.java new file mode 100644 index 000000000..956968e06 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/HPManager.java @@ -0,0 +1,87 @@ +package nautilus.game.arcade.game.games.moba.kit.hp; + +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.potion.PotionEffectType; + +public class HPManager implements Listener +{ + + // Health per 5 seconds. + private static final double HP5 = 0.66; + private static final double HP_KILL_FACTOR = 0.25; + + private final Moba _host; + + public HPManager(Moba host) + { + _host = host; + } + + @EventHandler + public void regeneration(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC_05 || !_host.IsLive()) + { + return; + } + + for (Player player : _host.GetPlayers(true)) + { + if (UtilPlayer.isSpectator(player)) + { + continue; + } + + MobaHPRegenEvent regenEvent = new MobaHPRegenEvent(player, null, HP5, true); + UtilServer.CallEvent(regenEvent); + + if (regenEvent.isCancelled()) + { + continue; + } + + player.setHealth(Math.min(player.getMaxHealth(), player.getHealth() + regenEvent.getHealth())); + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + Player killer = event.getEntity().getKiller(); + + if (killer == null) + { + return; + } + + killer.setHealth(Math.min(killer.getHealth() + killer.getMaxHealth() * HP_KILL_FACTOR, killer.getMaxHealth())); + } + + @EventHandler + public void preventHungerRegeneration(EntityRegainHealthEvent event) + { + if (event.getRegainReason() == RegainReason.SATIATED) + { + event.setCancelled(true); + } + } + + @EventHandler + public void preventRegenerationWither(MobaHPRegenEvent event) + { + if (event.getPlayer().hasPotionEffect(PotionEffectType.WITHER)) + { + event.setCancelled(true); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/MobaHPRegenEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/MobaHPRegenEvent.java new file mode 100644 index 000000000..2ef3e9875 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/hp/MobaHPRegenEvent.java @@ -0,0 +1,83 @@ +package nautilus.game.arcade.game.games.moba.kit.hp; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +public class MobaHPRegenEvent extends PlayerEvent implements Cancellable +{ + + private static final HandlerList _handlers = new HandlerList(); + + private final Player _source; + private final double _initialHealth; + private double _health; + private boolean _natural; + private boolean _cancel; + + public MobaHPRegenEvent(Player who, Player source, double health, boolean natural) + { + super(who); + + _source = source; + _initialHealth = health; + _health = health; + _natural = natural; + } + + public Player getSource() + { + return _source; + } + + public void setHealth(double health) + { + _health = health; + } + + public void increaseHealth(double factor) + { + _health = _initialHealth + (_initialHealth * factor); + } + + public double getHealth() + { + return _health; + } + + public void setNatural(boolean natural) + { + _natural = natural; + } + + public boolean isNatural() + { + return _natural; + } + + @Override + public boolean isCancelled() + { + return _cancel; + } + + @Override + public void setCancelled(boolean b) + { + _cancel = b; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/HeroLarissa.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/HeroLarissa.java new file mode 100644 index 000000000..a1f2cb08b --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/HeroLarissa.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.kit.larissa; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class HeroLarissa extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillAquaCannon(0), + new SkillAOEHeal(1), + new SkillWaterDash(2), + new SkillStormHeal(3) + }; + + private static final ItemStack AMMO = new ItemBuilder(Material.INK_SACK, (byte) 4) + .setTitle(C.cYellowB + "Water Stone") + .setUnbreakable(true) + .build(); + + public HeroLarissa(ArcadeManager manager) + { + super(manager, "Larissa", PERKS, MobaRole.MAGE, SkinData.LARISSA); + + setAmmo(AMMO, 3000); + setMaxAmmo(5); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAOEHeal.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAOEHeal.java new file mode 100644 index 000000000..93e4e5055 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAOEHeal.java @@ -0,0 +1,187 @@ +package nautilus.game.arcade.game.games.moba.kit.larissa; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilFirework; +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.UtilTime; +import mineplex.core.common.util.particles.ColoredParticle; +import mineplex.core.common.util.particles.DustSpellColor; +import mineplex.core.projectile.IThrown; +import mineplex.core.projectile.ProjectileUser; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaParticles; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.ChatColor; +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.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class SkillAOEHeal extends HeroSkill implements IThrown +{ + + private static final String[] DESCRIPTION = { + "Throws a water bucket which upon coming into", + "contact with the ground will heal nearby", + "players and minions." + }; + private static final long DURATION = TimeUnit.SECONDS.toMillis(6); + private static final int RADIUS = 3; + private static final int HEALTH_PER_SECOND = 4; + private static final int DAMAGE_PER_SECOND = 2; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.WATER_BUCKET); + private static final ItemStack THROWN_ITEM = new ItemStack(Material.WATER_BUCKET); + + private final Set _data = new HashSet<>(); + + public SkillAOEHeal(int slot) + { + super("Dancing Fountain", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(14000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + Vector direction = player.getLocation().getDirection(); + Item item = player.getWorld().dropItem(player.getEyeLocation().add(direction), THROWN_ITEM); + item.setVelocity(direction); + + useSkill(player); + Manager.GetProjectile().AddThrow(item, player, this, 1000, true, true, true, false, 1F); + } + + @Override + public void Collide(LivingEntity target, Block block, ProjectileUser data) + { + deployAoe((Player) data.getThrower(), data.getThrown(), data.getThrown().getLocation()); + } + + @Override + public void Idle(ProjectileUser data) + { + } + + @Override + public void Expire(ProjectileUser data) + { + deployAoe((Player) data.getThrower(), data.getThrown(), data.getThrown().getLocation()); + } + + @EventHandler + public void updateAOE(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + AOEHealData data = iterator.next(); + Player owner = data.Owner; + GameTeam team = Manager.GetGame().GetTeam(owner); + DustSpellColor colour = new DustSpellColor(team.GetColor() == ChatColor.RED ? java.awt.Color.RED : java.awt.Color.CYAN); + + if (UtilTime.elapsed(data.Start, DURATION)) + { + iterator.remove(); + } + else if (UtilTime.elapsed(data.LastHeal, 1000)) + { + data.LastHeal = System.currentTimeMillis(); + + for (LivingEntity entity : UtilEnt.getInRadius(data.Center, RADIUS).keySet()) + { + if (isTeamDamage(entity, owner)) + { + MobaParticles.healing(entity, HEALTH_PER_SECOND); + MobaUtil.heal(entity, owner, HEALTH_PER_SECOND); + } + else + { + Manager.GetDamage().NewDamageEvent(entity, owner, null, DamageCause.CUSTOM, DAMAGE_PER_SECOND, true, true, false, owner.getName(), GetName()); + } + } + } + + UtilParticle.PlayParticleToAll(ParticleType.DRIP_WATER, data.Center, RADIUS - 0.5F, 0.2F, RADIUS - 0.5F, 0.1F, 5, ViewDist.LONG); + + for (double theta = 0; theta < 2 * Math.PI; theta += Math.PI / 15) + { + double x = RADIUS * Math.cos(theta); + double z = RADIUS * Math.sin(theta); + + data.Center.add(x, 0, z); + + new ColoredParticle(ParticleType.RED_DUST, colour, data.Center).display(ViewDist.LONG); + + data.Center.subtract(x, 0, z); + } + } + } + + private void deployAoe(Player thrower, Entity item, Location location) + { + GameTeam team = Manager.GetGame().GetTeam(thrower); + + if (team == null) + { + return; + } + + UtilFirework.playFirework(location, FireworkEffect.builder().with(Type.BURST).withColor(team.GetColorBase()).withFade(Color.WHITE).withFlicker().build()); + thrower.getWorld().playSound(location, Sound.SPLASH2, 1, 1); + item.remove(); + _data.add(new AOEHealData(thrower, location)); + } + + private class AOEHealData + { + + Player Owner; + Location Center; + long Start; + long LastHeal; + + AOEHealData(Player owner, Location center) + { + Owner = owner; + Center = center; + Start = System.currentTimeMillis(); + LastHeal = Start; + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAquaCannon.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAquaCannon.java new file mode 100644 index 000000000..2a64ce53c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillAquaCannon.java @@ -0,0 +1,77 @@ +package nautilus.game.arcade.game.games.moba.kit.larissa; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilServer; +import mineplex.core.common.util.particles.effects.LineParticle; +import mineplex.core.recharge.Recharge; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerManager; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +public class SkillAquaCannon extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Fires a beam of water that deals damage", + "to the first enemy it comes in contact with." + }; + private static final int DAMAGE = 6; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.DIAMOND_HOE); + + public SkillAquaCannon(int slot) + { + super("Aqua Cannon", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + if (!_kit.useAmmo(player, 1)) + { + return; + } + + TowerManager towerManager = ((Moba) Manager.GetGame()).getTowerManager(); + Vector direction = player.getLocation().getDirection(); + + LineParticle lineParticle = new LineParticle(player.getLocation().add(0, 1.7, 0), direction, 0.2, 10, ParticleType.DRIP_WATER, UtilServer.getPlayers()); + + while (!lineParticle.update() && towerManager.damageTowerAt(lineParticle.getLastLocation(), player, DAMAGE) == null) + { + for (LivingEntity entity : UtilEnt.getInRadius(lineParticle.getLastLocation(), 2).keySet()) + { + if (isTeamDamage(entity, player)) + { + continue; + } + + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, DAMAGE, true, false, false, player.getName(), MobaConstants.BASIC_ATTACK); + break; + } + } + + player.getWorld().playSound(lineParticle.getLastLocation(), Sound.BLAZE_HIT, 1, 1.4F); + UtilParticle.PlayParticleToAll(ParticleType.FIREWORKS_SPARK, lineParticle.getLastLocation(), 0, 0, 0, 0.2F, 10, ViewDist.LONG); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillStormHeal.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillStormHeal.java new file mode 100644 index 000000000..a26b02cfe --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillStormHeal.java @@ -0,0 +1,133 @@ +package nautilus.game.arcade.game.games.moba.kit.larissa; + +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class SkillStormHeal extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "All team members are consistently healed", + "over the next 7 seconds." + }; + private static final long DURATION = TimeUnit.SECONDS.toMillis(7); + private static final int HEALTH_PER_SECOND = 2; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + + private final Map _active = new HashMap<>(); + + public SkillStormHeal(int slot) + { + super("Storm's Blessing", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event) || _active.containsKey(event.getPlayer())) + { + return; + } + + Player player = event.getPlayer(); + + for (Player teamMember : Manager.GetGame().GetTeam(player).GetPlayers(true)) + { + teamMember.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, (int) (DURATION / 50D), 0)); + } + + _active.put(player, System.currentTimeMillis()); + broadcast(player); + useActiveSkill(player, DURATION - 500); + } + + @EventHandler + public void updateHeal(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC) + { + return; + } + + _active.forEach((player, start) -> + { + GameTeam team = Manager.GetGame().GetTeam(player); + + if (team == null) + { + return; + } + + for (Player teamMember : team.GetPlayers(true)) + { + MobaUtil.heal(teamMember, player, HEALTH_PER_SECOND); + } + }); + } + + @EventHandler + public void updateParticles(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + Iterator iterator = _active.keySet().iterator(); + + while (iterator.hasNext()) + { + Player player = iterator.next(); + + if (UtilTime.elapsed(_active.get(player), DURATION)) + { + iterator.remove(); + } + + GameTeam team = Manager.GetGame().GetTeam(player); + + if (team == null) + { + return; + } + + for (Player teamMember : team.GetPlayers(true)) + { + if (UtilPlayer.isSpectator(teamMember)) + { + continue; + } + + Location location = teamMember.getLocation().add(0, 3, 0); + + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, location, 0.5F, 0.2F, 0.5F, 0.001F, 12, ViewDist.LONG); + UtilParticle.PlayParticleToAll(ParticleType.DRIP_WATER, location.subtract(0, 0.2, 0), 0.4F, 0.1F, 0.4F, 0.1F, 2, ViewDist.LONG); + } + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillWaterDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillWaterDash.java new file mode 100644 index 000000000..69cc3a8f4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/larissa/SkillWaterDash.java @@ -0,0 +1,57 @@ +package nautilus.game.arcade.game.games.moba.kit.larissa; + +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 nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.buff.BuffManager; +import nautilus.game.arcade.game.games.moba.buff.buffs.BuffCripple; +import nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.concurrent.TimeUnit; + +public class SkillWaterDash extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Dash along the ground, crippling enemies you", + "come into contact with." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + private static final long CRIPPLE_DURATION = TimeUnit.SECONDS.toMillis(3); + + public SkillWaterDash(int slot) + { + super("Water Dash", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(10000); + + _collide = false; + _velocityTime = 600; + _velocityStopOnEnd = true; + _horizontial = true; + } + + @Override + public void dashTick(Player player) + { + UtilParticle.PlayParticleToAll(ParticleType.DRIP_WATER, player.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5F, 0.01F, 5, ViewDist.LONG); + Moba moba = (Moba) Manager.GetGame(); + BuffManager buffManager = moba.getBuffManager(); + + for (Player nearby : UtilPlayer.getNearby(player.getLocation(), 2)) + { + if (isTeamDamage(nearby, player) || buffManager.hasBuff(nearby, BuffCripple.class)) + { + continue; + } + + buffManager.apply(new BuffCripple(moba, nearby, CRIPPLE_DURATION)); + } + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/HeroRowena.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/HeroRowena.java new file mode 100644 index 000000000..d15ab3174 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/HeroRowena.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.kit.rowena; + +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.common.SkillBow; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public class HeroRowena extends HeroKit +{ + + private static final Perk[] PERKS = { + new SkillBow(0), + new SkillLightArrows(1), + new SkillCombatDash(2), + new SkillBombardment(3) + }; + + private static final ItemStack AMMO = new ItemBuilder(Material.ARROW) + .setTitle(C.cYellowB + "Hunting Arrow") + .setUnbreakable(true) + .build(); + + public HeroRowena(ArcadeManager manager) + { + super(manager, "Rowena", PERKS, MobaRole.HUNTER, SkinData.ROWENA); + + setAmmo(AMMO, 2000); + setMaxAmmo(2); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillBombardment.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillBombardment.java new file mode 100644 index 000000000..cdb3e4838 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillBombardment.java @@ -0,0 +1,209 @@ +package nautilus.game.arcade.game.games.moba.kit.rowena; + +import mineplex.core.common.events.EntityVelocityChangeEvent; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +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.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.particles.effects.LineParticle; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +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.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class SkillBombardment extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Take to the sky!", + "Your shots become fast high power explosive shots." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.NETHER_STAR); + private static final int DAMAGE_FACTOR = 2; + private static final int SHOTS = 3; + private static final int MAX_TIME = 10000; + private static final ItemStack ACTIVE_ITEM = new ItemBuilder(Material.DIAMOND_BARDING) + .setTitle(C.cDRedB + "Bombardment") + .build(); + + private Set _data = new HashSet<>(); + + public SkillBombardment(int slot) + { + super("Bombardment", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(60000); + setDropItemActivate(true); + } + + @Override + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + for (BombardmentData data : _data) + { + if (data.Shooter.equals(player)) + { + return; + } + } + + Location toTeleport = player.getLocation().add(0, 15, 0); + + player.teleport(toTeleport); + player.getInventory().setItem(0, ACTIVE_ITEM); + player.getInventory().setHeldItemSlot(0); + broadcast(player); + _data.add(new BombardmentData(player)); + } + + @EventHandler + public void interactActive(PlayerInteractEvent event) + { + if (event.getItem() == null || !event.getItem().isSimilar(ACTIVE_ITEM)) + { + return; + } + + Player player = event.getPlayer(); + + for (BombardmentData data : _data) + { + if (data.Shooter.equals(player)) + { + Location location = player.getEyeLocation(); + LineParticle lineParticle = new LineParticle(location, location.getDirection(), 0.4, 40, ParticleType.FIREWORKS_SPARK, UtilServer.getPlayers()); + double damage = MobaUtil.scaleDamageWithBow(player.getInventory().getItem(0), 0) * DAMAGE_FACTOR; + + while (!lineParticle.update()) + { + } + + player.playSound(player.getLocation(), Sound.EXPLODE, 1, 0.8F); + UtilParticle.PlayParticleToAll(ParticleType.HUGE_EXPLOSION, lineParticle.getDestination(), 0, 0, 0, 0.1F, 1, ViewDist.LONG); + + for (LivingEntity entity : UtilEnt.getInRadius(lineParticle.getLastLocation(), 5).keySet()) + { + if (isTeamDamage(entity, player)) + { + continue; + } + + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, damage, true, true, false, player.getName(), GetName()); + } + + data.Shots--; + return; + } + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _data.iterator(); + + while (iterator.hasNext()) + { + BombardmentData data = iterator.next(); + Player player = data.Shooter; + + if (UtilTime.elapsed(data.Start, MAX_TIME) || data.Shots <= 0) + { + useSkill(player); + Kit.GiveItems(player); + data.Block.setType(Material.AIR); + iterator.remove(); + } + else if (data.Block != null) + { + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, data.Block.getLocation().add(0.5, 0.5, 0.5), 0.5F, 0.5F, 0.5F, 0.001F, 3, ViewDist.LONG); + } + } + } + + @EventHandler + public void playerMove(PlayerMoveEvent event) + { + Player player = event.getPlayer(); + + for (BombardmentData data : _data) + { + if (data.Block != null && data.Shooter.equals(player) && (event.getTo().getX() != event.getFrom().getX() || event.getTo().getZ() != event.getFrom().getZ())) + { + event.setTo(event.getFrom()); + } + } + } + + @EventHandler + public void playerVelocity(EntityVelocityChangeEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + for (BombardmentData data : _data) + { + if (data.Block != null && data.Shooter.equals(player)) + { + event.setCancelled(true); + } + } + } + + private class BombardmentData + { + + Player Shooter; + int Shots; + Block Block; + long Start; + + BombardmentData(Player shooter) + { + Shooter = shooter; + Shots = SHOTS; + Block = shooter.getLocation().getBlock().getRelative(BlockFace.DOWN); + Block.setType(Material.BARRIER); + Start = System.currentTimeMillis(); + } + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillCombatDash.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillCombatDash.java new file mode 100644 index 000000000..a3edb19df --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillCombatDash.java @@ -0,0 +1,39 @@ +package nautilus.game.arcade.game.games.moba.kit.rowena; + +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import nautilus.game.arcade.game.games.moba.kit.common.DashSkill; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class SkillCombatDash extends DashSkill +{ + + private static final String[] DESCRIPTION = { + "Dash very fast along the ground.", + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.FEATHER); + + public SkillCombatDash(int slot) + { + super("Combat Slide", DESCRIPTION, SKILL_ITEM, slot); + + setCooldown(8000); + + _collide = false; + _velocityTime = 250; + _velocityMagnitude = 1.5; + _horizontial = true; + } + + @Override + public void preDash(Player player) + { + UtilParticle.PlayParticleToAll(ParticleType.CLOUD, player.getLocation().add(0, 1, 0), 0.5F, 0.5F, 0.5F, 0.001F, 20, ViewDist.LONG); + player.getWorld().playSound(player.getLocation(), Sound.BAT_TAKEOFF, 1, 1); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillLightArrows.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillLightArrows.java new file mode 100644 index 000000000..d4037aa5f --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/kit/rowena/SkillLightArrows.java @@ -0,0 +1,174 @@ +package nautilus.game.arcade.game.games.moba.kit.rowena; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilInv; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.particles.effects.LineParticle; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.structure.tower.Tower; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerManager; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class SkillLightArrows extends HeroSkill +{ + + private static final String[] DESCRIPTION = { + "Your next 5 arrows become light infused.", + "They pass through blocks and deal high damage." + }; + private static final ItemStack SKILL_ITEM = new ItemStack(Material.GOLD_NUGGET); + + private final Map _playerArrows = new HashMap<>(); + private final Map> _arrows = new HashMap<>(); + + public SkillLightArrows(int slot) + { + super("Light Arrows", DESCRIPTION, SKILL_ITEM, slot, ActionType.ANY); + + setCooldown(12000); + } + + @EventHandler + public void interact(PlayerInteractEvent event) + { + if (!isSkillItem(event)) + { + return; + } + + Player player = event.getPlayer(); + + _playerArrows.put(player, 5); + UtilInv.addDullEnchantment(player.getItemInHand()); + player.getItemInHand().setAmount(5); + } + + @EventHandler + public void shootArrow(EntityShootBowEvent event) + { + if (!(event.getEntity() instanceof Player)) + { + return; + } + + Player player = (Player) event.getEntity(); + + if (!hasPerk(player) || !_playerArrows.containsKey(player)) + { + return; + } + + ItemStack itemStack = player.getInventory().getItem(getSlot()); + int arrows = _playerArrows.get(player); + + if (arrows == 1) + { + _playerArrows.remove(player); + useSkill(player); + } + else + { + arrows--; + _playerArrows.put(player, arrows); + itemStack.setAmount(arrows); + } + + event.getProjectile().remove(); + + LineParticle lineParticle = new LineParticle(player.getEyeLocation(), player.getLocation().getDirection(), 0.4, 40, ParticleType.FIREWORKS_SPARK, UtilServer.getPlayers()); + lineParticle.setIgnoreAllBlocks(true); + + _arrows.putIfAbsent(player, new HashSet<>()); + _arrows.get(player).add(lineParticle); + } + + @EventHandler + public void updateArrows(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + TowerManager towerManager = ((Moba) Manager.GetGame()).getTowerManager(); + + for (Entry> entry : _arrows.entrySet()) + { + Player player = entry.getKey(); + Iterator iterator = entry.getValue().iterator(); + double damage = MobaUtil.scaleDamageWithBow(player.getInventory().getItem(0), 0); + + lineParticleLoop : while (iterator.hasNext()) + { + LineParticle lineParticle = iterator.next(); + + for (int i = 0; i < 4; i++) + { + if (!lineParticle.update()) + { + Tower hitTower = towerManager.damageTowerAt(lineParticle.getLastLocation(), player, damage); + + if (hitTower != null && UtilMath.offsetSquared(hitTower.getCrystal(), player) > Tower.TARGET_RANGE_SQUARED) + { + continue; + } + + for (LivingEntity entity : UtilEnt.getInRadius(lineParticle.getLastLocation(), 1.5).keySet()) + { + if (Recharge.Instance.use(player, GetName() + entity.getUniqueId(), 500, false, false)) + { + player.playSound(player.getLocation(), Sound.SUCCESSFUL_HIT, 1, 0.8F); + Manager.GetDamage().NewDamageEvent(entity, player, null, DamageCause.CUSTOM, damage, true, true, false, player.getName(), GetName()); + } + } + } + else + { + iterator.remove(); + continue lineParticleLoop; + } + } + } + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + _playerArrows.remove(event.getEntity()); + _arrows.remove(event.getEntity()); + } + + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + _playerArrows.remove(event.getPlayer()); + _arrows.remove(event.getPlayer()); + } +} + diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/Minion.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/Minion.java new file mode 100644 index 000000000..d8092f1b1 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/Minion.java @@ -0,0 +1,87 @@ +package nautilus.game.arcade.game.games.moba.minion; + +import mineplex.core.common.util.UtilEnt; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Zombie; +import org.bukkit.inventory.ItemStack; + +public class Minion +{ + + private static final int HEALTH = 10; + private static final float HIT_BOX = 2F; + private static final ItemStack[] SUPER_ARMOUR = { + new ItemStack(Material.IRON_BOOTS), + new ItemStack(Material.IRON_LEGGINGS), + new ItemStack(Material.IRON_CHESTPLATE), + new ItemStack(Material.IRON_HELMET) + }; + + private final LivingEntity _entity; + + private Location _target; + private int _targetIndex; + + public Minion(Location spawn, Class clazz, boolean superMinion) + { + _target = spawn; + + LivingEntity entity = spawn.getWorld().spawn(spawn, clazz); + _entity = entity; + entity.setMaxHealth(HEALTH); + entity.setRemoveWhenFarAway(false); + + if (entity instanceof Zombie) + { + ((Zombie) entity).setBaby(true); + } + + if (superMinion) + { + entity.getEquipment().setArmorContents(SUPER_ARMOUR); + } + + UtilEnt.vegetate(entity); + UtilEnt.silence(entity, true); + UtilEnt.setBoundingBox(entity, HIT_BOX, HIT_BOX); + + entity.setCustomNameVisible(true); + updateDisplay(entity.getMaxHealth()); + } + + public void updateDisplay(double health) + { + _entity.setCustomName(MobaUtil.getHealthBar(_entity, health, 10)); + } + + public LivingEntity getEntity() + { + return _entity; + } + + public void setTarget(Location location) + { + // Keep the Y constant + location.setY(_target.getY()); + + _target = location; + } + + public Location getTarget() + { + return _target; + } + + public void setTargetIndex(int index) + { + _targetIndex = index; + } + + public int getTargetIndex() + { + return _targetIndex; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionManager.java new file mode 100644 index 000000000..e3c663632 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionManager.java @@ -0,0 +1,195 @@ +package nautilus.game.arcade.game.games.moba.minion; + +import mineplex.core.common.Rank; +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.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GamePrepareCountdownCommence; +import nautilus.game.arcade.game.DebugCommand; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.structure.tower.Tower; +import nautilus.game.arcade.game.games.moba.structure.tower.TowerDestroyEvent; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +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.PigZombie; +import org.bukkit.entity.Player; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class MinionManager implements Listener +{ + + private static final int MINION_SPAWN_DELAY_TICKS = 40; + private static final long MINION_SPAWN_TIME = TimeUnit.SECONDS.toMillis(30); + + private final Moba _host; + + private List _path; + private final Set _waves; + + private long _lastWave; + private boolean _enabled; + + public MinionManager(Moba host) + { + _host = host; + _waves = new HashSet<>(); + + host.registerDebugCommand(new DebugCommand("removeminions", Rank.DEVELOPER) + { + @Override + public void Execute(Player caller, String[] args) + { + for (MinionWave wave : _waves) + { + wave.cleanup(); + } + + caller.sendMessage(F.main("Debug", "Removed all minions.")); + } + }); + } + + @EventHandler + public void gameCountdownCommence(GamePrepareCountdownCommence event) + { + UtilServer.runSyncLater(() -> setEnabled(true), MINION_SPAWN_DELAY_TICKS); + } + + @EventHandler + public void spawnMinions(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || !_enabled || !_host.IsLive() || !UtilTime.elapsed(_lastWave, MINION_SPAWN_TIME)) + { + return; + } + + _lastWave = System.currentTimeMillis(); + + for (GameTeam team : _host.GetTeamList()) + { + List path = new ArrayList<>(_path); + boolean reverse = team.GetColor() == ChatColor.RED; + boolean superMinions = true; + + for (Tower tower : _host.getTowerManager().getTowers()) + { + if (!tower.isDead() && !tower.getOwner().equals(team)) + { + superMinions = false; + break; + } + } + + // If red team, reverse the pat + if (reverse) + { + Collections.reverse(path); + } + + MinionWave wave = new MinionWave(_host, this, team, path, reverse ? Zombie.class : PigZombie.class, superMinions); + + _waves.add(wave); + } + } + + @EventHandler + public void towerDestroy(TowerDestroyEvent event) + { + Tower tower = event.getTower(); + + if (tower.isFirstTower()) + { + return; + } + + for (GameTeam team : _host.GetTeamList()) + { + if (team.equals(tower.getOwner())) + { + continue; + } + + _host.Announce(F.main("Game", team.GetFormattedName() + "'s " + C.mBody + "minions are now " + C.cYellowB + "Super-Charged" + C.mBody + "!"), false); + } + } + + public void setEnabled(boolean enabled) + { + _enabled = enabled; + + if (enabled) + { + preparePath(); + } + } + + public void unregisterWave(MinionWave wave) + { + for (Minion minion : wave.getMinions()) + { + minion.getEntity().remove(); + } + + _waves.remove(wave); + } + + public Set getWaves() + { + return _waves; + } + + /** + * This method fills the {@link #_path} with the organised list of locations that the minions must follow.
+ *

+ * This says that the blue team is the start and the red team is the end. + */ + private void preparePath() + { + // Step 1 - Find the starting location for the blue team + Location start = _host.WorldData.GetDataLocs(MobaConstants.MINION_PATH_START).get(0); + + // Step 2 - Fill a list with ordered locations, from blue to red + ArrayList path = new ArrayList<>(_host.WorldData.GetDataLocs(MobaConstants.MINION_PATH)); + ArrayList organisedPath = new ArrayList<>(path.size()); + + while (!path.isEmpty()) + { + Location dataPoint = UtilAlg.findClosest(start, path); + + organisedPath.add(dataPoint); + path.remove(dataPoint); + start = dataPoint; + } + + // Step 3 - Put the ordered path inside the map + _path = organisedPath; + +// int i = 0; +// for (Location location : _path) +// { +// Block block = location.getBlock(); +// block.setType(Material.SIGN_POST); +// Sign sign = (Sign) block.getState(); +// sign.setLine(0, "P" + i++); +// sign.update(); +// } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionWave.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionWave.java new file mode 100644 index 000000000..5d9f3e77f --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/minion/MinionWave.java @@ -0,0 +1,472 @@ +package nautilus.game.arcade.game.games.moba.minion; + +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaAIMethod; +import nautilus.game.arcade.game.games.moba.ai.goal.MobaDirectAIMethod; +import nautilus.game.arcade.game.games.moba.boss.MobaBoss; +import nautilus.game.arcade.game.games.moba.boss.wither.WitherBoss; +import nautilus.game.arcade.game.games.moba.structure.tower.Tower; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import org.jooq.util.derby.sys.Sys; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class MinionWave implements Listener +{ + + private static final int MAX_MINIONS_PER_WAVE = 6; + private static final int TOO_CLOSE_SQUARED = 9; + private static final int DAMAGE_RANGE_SQUARED = 16; + private static final double DAMAGE_AMOUNT = 0.2; + private static final MobaAIMethod AI_METHOD = new MobaDirectAIMethod(); + + private final Moba _host; + private final MinionManager _minionManager; + private final GameTeam _owner; + private final Class _clazz; + private final boolean _superMinions; + private final long _startTime; + + private final List _path; + private final List _minions; + + public MinionWave(Moba host, MinionManager minionManager, GameTeam owner, List path, Class clazz, boolean superMinions) + { + _host = host; + _minionManager = minionManager; + _owner = owner; + _clazz = clazz; + _superMinions = superMinions; + _startTime = System.currentTimeMillis(); + _path = path; + _minions = new ArrayList<>(MAX_MINIONS_PER_WAVE); + + UtilServer.RegisterEvents(this); + + spawn(); + + UtilServer.runSyncTimer(new BukkitRunnable() + { + + @Override + public void run() + { + if (spawn()) + { + cancel(); + } + } + }, 15, 15); + } + + private boolean spawn() + { + _host.CreatureAllowOverride = true; + + Minion minion = new Minion(_path.get(0), _clazz, _superMinions); + MobaUtil.setTeamEntity(minion.getEntity(), _owner); + _minions.add(minion); + + _host.CreatureAllowOverride = false; + + return _minions.size() >= MAX_MINIONS_PER_WAVE; + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + for (Minion minion : _minions) + { + LivingEntity entity = minion.getEntity(); + Location target = null; + Location towerTarget = targetTower(minion); + Minion minionTarget = targetMinion(minion); + Location witherTarget = targetWither(minion); + + // Priority -> Tower -> Minion -> Wither + + if (towerTarget != null) + { + target = towerTarget; + } + else if (minionTarget != null) + { + target = minionTarget.getEntity().getLocation(); + minion.setTarget(target); + } + else if (witherTarget != null) + { + target = witherTarget; + } + + if (target != null) + { + minion.setTarget(target); + + // Too close + if (UtilMath.offsetSquared(entity.getLocation(), target) < TOO_CLOSE_SQUARED) + { + continue; + } + } + + if (!AI_METHOD.updateMovement(entity, minion.getTarget(), 4F)) + { + int newTarget = minion.getTargetIndex() + 1; + + if (newTarget == _path.size()) + { + continue; + } + + minion.setTargetIndex(newTarget); + minion.setTarget(_path.get(newTarget)); + } + } + } + + @EventHandler + public void updateUnregister(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + Iterator iterator = _minions.iterator(); + + while (iterator.hasNext()) + { + Minion minion = iterator.next(); + LivingEntity entity = minion.getEntity(); + + if (entity == null || entity.isDead() || !entity.isValid()) + { + if (entity != null && entity.getKiller() != null) + { + _host.AddGems(entity.getKiller(), 0.1, "Minion Kills", true, true); + } + + iterator.remove(); + } + } + + // Only should unregister the wave after all entities have spawned + if (_minions.isEmpty() && UtilTime.elapsed(_startTime, 10000)) + { + UtilServer.Unregister(this); + _minionManager.unregisterWave(this); + } + } + + private Minion targetMinion(Minion minion) + { + for (MinionWave wave : _minionManager.getWaves()) + { + // Same team + if (wave.getOwner().equals(_owner)) + { + continue; + } + + for (Minion otherMinion : wave.getMinions()) + { + double distSquared = UtilMath.offsetSquared(minion.getEntity(), otherMinion.getEntity()); + + if (distSquared < 3) + { + return otherMinion; + } + else if (distSquared > Tower.TARGET_RANGE_SQUARED) + { + continue; + } + + return otherMinion; + } + } + + return null; + } + + private Location targetTower(Minion minion) + { + for (Tower tower : _host.getTowerManager().getTowers()) + { + if (tower.isDead() || tower.getOwner().equals(_owner)) + { + continue; + } + + Location location = tower.getCrystal().getLocation(); + double distSquared = UtilMath.offsetSquared(minion.getEntity(), tower.getCrystal()); + + if (distSquared < 3) + { + return location; + } + else if (distSquared > Tower.TARGET_RANGE_SQUARED) + { + continue; + } + + return location; + } + + return null; + } + + private Location targetWither(Minion minion) + { + for (MobaBoss boss : _host.getBossManager().getBosses()) + { + if (boss.isDead() || !(boss instanceof WitherBoss)) + { + continue; + } + + WitherBoss witherBoss = (WitherBoss) boss; + + if (witherBoss.getTeam().equals(_owner)) + { + continue; + } + + Location location = boss.getEntity().getLocation(); + double distSquared = UtilMath.offsetSquared(minion.getEntity(), boss.getEntity()); + + if (distSquared < 3) + { + return location; + } + else if (distSquared > Tower.TARGET_RANGE_SQUARED) + { + continue; + } + + return location; + } + + return null; + } + + @EventHandler + public void damageMinions(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (Minion minion : _minions) + { + for (MinionWave wave : _minionManager.getWaves()) + { + // Same team + if (wave.getOwner().equals(_owner)) + { + continue; + } + + for (Minion otherMinion : wave.getMinions()) + { + // Cannot damage, not close enough + if (UtilMath.offsetSquared(minion.getEntity(), otherMinion.getEntity()) > DAMAGE_RANGE_SQUARED) + { + continue; + } + + _host.getArcadeManager().GetDamage().NewDamageEvent(otherMinion.getEntity(), minion.getEntity(), null, DamageCause.CUSTOM, DAMAGE_AMOUNT, false, true, false, UtilEnt.getName(minion.getEntity()), "Minion"); + } + } + } + + for (Minion minion : _minions) + { + for (Tower tower : _host.getTowerManager().getTowers()) + { + // Cannot damage, not close enough + if (!_host.getTowerManager().canDamage(tower, _owner) || UtilMath.offsetSquared(minion.getEntity(), tower.getCrystal()) > DAMAGE_RANGE_SQUARED) + { + continue; + } + + tower.damage(DAMAGE_AMOUNT); + } + } + } + + @EventHandler + public void damageTower(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (Minion minion : _minions) + { + for (Tower tower : _host.getTowerManager().getTowers()) + { + // Cannot damage, not close enough + if (!_host.getTowerManager().canDamage(tower, _owner) || UtilMath.offsetSquared(minion.getEntity(), tower.getCrystal()) > DAMAGE_RANGE_SQUARED) + { + continue; + } + + tower.damage(DAMAGE_AMOUNT); + } + } + } + + @EventHandler + public void damageWither(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + List bosses = _host.getBossManager().getBosses(); + + for (Minion minion : _minions) + { + for (MobaBoss boss : bosses) + { + // Dead, not close enough + if (boss.isDead() || UtilMath.offsetSquared(minion.getEntity(), boss.getEntity()) > DAMAGE_RANGE_SQUARED) + { + continue; + } + + _host.getArcadeManager().GetDamage().NewDamageEvent(boss.getEntity(), minion.getEntity(), null, DamageCause.CUSTOM, DAMAGE_AMOUNT, false, false, false, UtilEnt.getName(minion.getEntity()), "Minion"); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void damage(CustomDamageEvent event) + { + // Not a Minion + if (event.isCancelled() || !isMinion(event.GetDamageeEntity())) + { + return; + } + + LivingEntity damagee = event.GetDamageeEntity(); + Player damager = event.GetDamagerPlayer(true); + GameTeam team = _host.GetTeam(damager); + + if (team != null && _owner.equals(team)) + { + event.SetCancelled("Same Team Minion"); + } + else + { + Minion minion = getMinion(damagee); + + if (minion != null) + { + minion.updateDisplay(minion.getEntity().getHealth() - event.GetDamage()); + } + } + } + + @EventHandler + public void entityCombust(EntityCombustEvent event) + { + if (isMinion(event.getEntity())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void suffocation(CustomDamageEvent event) + { + if (isMinion(event.GetDamageeEntity()) && event.GetCause() == DamageCause.SUFFOCATION) + { + event.SetCancelled("Minion Suffocation"); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void entityDeath(EntityDeathEvent event) + { + if (!isMinion(event.getEntity())) + { + return; + } + + event.getDrops().clear(); + event.setDroppedExp(0); + } + + public void cleanup() + { + for (Minion minion : _minions) + { + minion.getEntity().remove(); + } + } + + public List getMinions() + { + return _minions; + } + + public GameTeam getOwner() + { + return _owner; + } + + private Minion getMinion(Entity entity) + { + for (Minion minion : _minions) + { + if (entity.equals(minion.getEntity())) + { + return minion; + } + } + + return null; + } + + private boolean isMinion(Entity entity) + { + return getMinion(entity) != null; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareManager.java new file mode 100644 index 000000000..eacc7cdd0 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareManager.java @@ -0,0 +1,168 @@ +package nautilus.game.arcade.game.games.moba.prepare; + +import mineplex.core.common.entity.ClientArmorStand; +import mineplex.core.common.util.*; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GamePrepareCountdownCommence; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaPlayer; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.HeroSkill; +import nautilus.game.arcade.game.games.moba.kit.RoleSelectEvent; +import nautilus.game.arcade.kit.Kit; +import nautilus.game.arcade.kit.Perk; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; + +import java.util.concurrent.TimeUnit; + +public class PrepareManager implements Listener +{ + + private static final long PREPARE_TIME = TimeUnit.MINUTES.toMillis(1); + private static final long POST_SELECTION_PREPARE_TIME = TimeUnit.SECONDS.toMillis(5); + private static final int MAX_DISTANCE_WITHOUT_SELECTION_SQUARED = 400; + + private final Moba _host; + + private boolean _postPrepareStage; + + public PrepareManager(Moba host) + { + _host = host; + } + + @EventHandler(priority = EventPriority.LOW) + public void updatePrepare(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || _host.GetState() != GameState.Prepare || _postPrepareStage) + { + return; + } + + if (!UtilTime.elapsed(_host.GetStateTime(), PREPARE_TIME)) + { + for (Player player : _host.GetPlayers(true)) + { + Kit kit = _host.GetKit(player); + + if (!(kit instanceof HeroKit)) + { + return; + } + } + } + + _postPrepareStage = true; + + _host.AnnounceGame(); + _host.StartPrepareCountdown(); + + //Event + GamePrepareCountdownCommence countdownEvent = new GamePrepareCountdownCommence(_host); + UtilServer.CallEvent(countdownEvent); + + // If players took too long, just give them a random free role and kit. + for (Player player : _host.GetPlayers(true)) + { + Kit kit = _host.GetKit(player); + + if (kit instanceof HeroKit) + { + continue; + } + + HeroKit heroKit = _host.getFirstKit(player); + MobaPlayer mobaPlayer = _host.getMobaData(player); + + mobaPlayer.setRole(heroKit.getRole()); + + _host.SetKit(player, heroKit, true); + } + + for (GameTeam team : _host.GetTeamList()) + { + team.SpawnTeleport(); + } + + _host.SetStateTime(System.currentTimeMillis()); + _host.getArcadeManager().GetChat().Silence(-1, false); + _host.PrepareTime = POST_SELECTION_PREPARE_TIME; + _host.PrepareFreeze = true; + } + + @EventHandler + public void updateNearSpawn(UpdateEvent event) + { + if (event.getType() != UpdateType.SLOW || _host.GetState() != GameState.Prepare) + { + return; + } + + for (MobaPlayer mobaPlayer : _host.getMobaData()) + { + Player player = mobaPlayer.getPlayer(); + GameTeam team = _host.GetTeam(player); + + if (UtilMath.offsetSquared(player.getLocation(), team.GetSpawns().get(0)) > MAX_DISTANCE_WITHOUT_SELECTION_SQUARED && (mobaPlayer.getRole() == null || mobaPlayer.getKit() == null)) + { + player.sendMessage(F.main("Game", "You haven't finished selecting your hero.")); + team.SpawnTeleport(player); + } + } + } + + @EventHandler + public void roleSelect(RoleSelectEvent event) + { + Player player = event.getPlayer(); + MobaRole role = event.getRole(); + ClientArmorStand stand = event.getStand(); + + if (!_host.isRoleFree(player, role)) + { + player.sendMessage(F.main("Game", "Another player has already chosen this role.")); + event.setCancelled(true); + return; + } + + // Show that the kit is claimed. + stand.setCustomName(C.cGreenB + role.getName() + C.cGray + " - " + player.getName()); + + // Store the role of the player + _host.getMobaData(player).setRole(role); + + // Update the scoreboard + _host.getScoreboardModule().refreshAsSubject(player); + } + + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Live) + { + return; + } + + for (MobaPlayer mobaPlayer : _host.getMobaData()) + { + HeroKit kit = mobaPlayer.getKit(); + Perk perk = kit.GetPerks()[kit.GetPerks().length - 1]; + + // Put Ultimates on cooldown + if (perk instanceof HeroSkill) + { + ((HeroSkill) perk).useSkill(mobaPlayer.getPlayer()); + } + } + + _host.getArcadeManager().GetChat().Silence(0, true); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareSelection.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareSelection.java new file mode 100644 index 000000000..23f01e5e9 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/prepare/PrepareSelection.java @@ -0,0 +1,274 @@ +package nautilus.game.arcade.game.games.moba.prepare; + +import mineplex.core.common.entity.ClientArmorStand; +import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.packethandler.IPacketHandler; +import mineplex.core.packethandler.PacketHandler.ListenerPriority; +import mineplex.core.packethandler.PacketInfo; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaPlayer; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.kit.RoleSelectEvent; +import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity; +import org.bukkit.ChatColor; +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.Listener; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; + +public class PrepareSelection implements Listener, IPacketHandler +{ + + private final Moba _host; + private final Map _roleStands = new HashMap<>(); + private final Map _kitStands = new HashMap<>(); + + public PrepareSelection(Moba host) + { + _host = host; + + _host.getArcadeManager().getPacketHandler().addPacketHandler(this, ListenerPriority.NORMAL, true, PacketPlayInUseEntity.class); + } + + // Setup + @EventHandler(priority = EventPriority.HIGHEST) + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (GameTeam team : _host.GetTeamList()) + { + spawnRoleUI(team); + } + } + + private void spawnRoleUI(GameTeam team) + { + Map spawns = _host.getLocationStartsWith("KIT " + team.GetName().toUpperCase()); + Location average = UtilAlg.getAverageLocation(team.GetSpawns()); + Player[] players = team.GetPlayers(true).toArray(new Player[0]); + + ItemStack head = new ItemBuilder(Material.SKULL_ITEM, (byte) 3).build(); + + UtilServer.runSyncLater(() -> + { + for (Player player : team.GetPlayers(true)) + { + displayRoleInformation(player); + } + + for (Entry entry : spawns.entrySet()) + { + Location location = entry.getValue(); + + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, average))); + + MobaRole role = MobaRole.valueOf(entry.getKey().split(" ")[2]); + ClientArmorStand stand = ClientArmorStand.spawn(prepareLocation(location), players); + + stand.setCustomNameVisible(true); + stand.setCustomName(C.cGreenB + role.getName() + C.cGray + " - " + C.cGreenB + "AVAILABLE"); + stand.setArms(true); + stand.setHelmet(head); + stand.setChestplate(buildColouredStack(Material.LEATHER_CHESTPLATE, role)); + stand.setLeggings(buildColouredStack(Material.LEATHER_LEGGINGS, role)); + stand.setBoots(buildColouredStack(Material.LEATHER_BOOTS, role)); + + _roleStands.put(stand, role); + } + // Only spawn the NPCs once all players have been loaded into the world. + }, _host.GetPlayers(true).size() * _host.TickPerTeleport + 10); + } + + private void spawnKitUI(Player player) + { + AtomicInteger i = new AtomicInteger(); + GameTeam team = _host.GetTeam(player); + Map spawns = _host.getLocationStartsWith("KIT " + team.GetName().toUpperCase()); + Location average = UtilAlg.getAverageLocation(team.GetSpawns()); + + MobaPlayer mobaPlayer = _host.getMobaData(player); + + List heroKits = _host.getKits(mobaPlayer.getRole()); + + ItemStack head = new ItemBuilder(Material.SKULL_ITEM, (byte) 2).build(); + + UtilServer.runSyncLater(() -> + { + for (Location location : spawns.values()) + { + location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, average))); + + HeroKit kit = heroKits.get(i.getAndIncrement()); + ClientArmorStand stand = ClientArmorStand.spawn(location.clone().add(0, 1, 0), player); + + stand.setCustomNameVisible(true); + stand.setCustomName(C.cGreenB + kit.GetName()); + stand.setArms(true); + stand.setHelmet(head); +// stand.setChestplate(buildColouredStack(Material.LEATHER_CHESTPLATE, role)); +// stand.setLeggings(buildColouredStack(Material.LEATHER_LEGGINGS, role)); +// stand.setBoots(buildColouredStack(Material.LEATHER_BOOTS, role)); + player.playSound(player.getLocation(), Sound.LEVEL_UP, 1, 0.5F); + UtilParticle.PlayParticle(ParticleType.CLOUD, location.clone().add(0, 2, 0), 0.5F, 0.5F, 0.5F, 0.01F, 20, ViewDist.LONG, player); + + _kitStands.put(stand, kit); + + if (i.get() == heroKits.size()) + { + break; + } + } + }, 20); + } + + private Location prepareLocation(Location location) + { + Block block = location.getBlock(); + + block.setType(Material.SMOOTH_BRICK); + block.setData((byte) 3); + + return location.clone().add(0, 1, 0); + } + + private ItemStack buildColouredStack(Material material, MobaRole role) + { + return new ItemBuilder(material).setColor(role.getColor()).build(); + } + + private void removePodiums() + { + _host.getLocationStartsWith("KIT").forEach((key, location) -> location.getBlock().setType(Material.AIR)); + } + + // Listen for those packety clicks + @Override + public void handle(PacketInfo packetInfo) + { + PacketPlayInUseEntity packet = (PacketPlayInUseEntity) packetInfo.getPacket(); + Player player = packetInfo.getPlayer(); + int entityId = packet.a; + + for (ClientArmorStand stand : _roleStands.keySet()) + { + if (stand.getEntityId() != entityId) + { + continue; + } + + packetInfo.setCancelled(true); + + MobaRole role = _roleStands.get(stand); + RoleSelectEvent event = new RoleSelectEvent(player, stand, role); + UtilServer.CallEvent(event); + + if (event.isCancelled()) + { + return; + } + + for (ClientArmorStand stand2 : _roleStands.keySet()) + { + stand2.remove(player); + } + + GameTeam team = _host.GetTeam(player); + + if (team == null) + { + return; + } + + if (team.GetColor() == ChatColor.RED) + { + spawnKitUI(player); + } + else + { + spawnKitUI(player); + } + + displayKitInformation(player, role); + } + + for (ClientArmorStand stand : _kitStands.keySet()) + { + if (stand.getEntityId() != entityId) + { + continue; + } + + packetInfo.setCancelled(true); + + HeroKit kit = _kitStands.get(stand); + + for (ClientArmorStand stand2 : _kitStands.keySet()) + { + stand2.remove(player); + } + + _host.SetKit(player, kit, true); + } + } + + private void displayRoleInformation(Player player) + { + String base = "Select the role you would like to play!"; + + UtilTextMiddle.display(C.cYellowB + "Role", base, 10, 40, 10, player); + player.sendMessage(F.main("Game", base)); + } + + private void displayKitInformation(Player player, MobaRole role) + { + String base = "Select your " + role.getChatColor() + "Hero"; + + UtilTextMiddle.display(role.getChatColor() + role.getName(), "Select your " + role.getChatColor() + "Hero", 10, 40, 10, player); + player.sendMessage(F.main("Game", base + C.mBody + "!")); + } + + // Unregister + @EventHandler + public void live(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Live) + { + return; + } + + for (ClientArmorStand stand : _roleStands.keySet()) + { + stand.remove(); + } + + for (ClientArmorStand stand : _kitStands.keySet()) + { + stand.remove(); + } + + removePodiums(); + _host.getArcadeManager().getPacketHandler().removePacketHandler(this); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/Recall.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/Recall.java new file mode 100644 index 000000000..2725ecf1f --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/Recall.java @@ -0,0 +1,153 @@ +package nautilus.game.arcade.game.games.moba.recall; + +import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilEvent.ActionType; +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.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Set; + +public class Recall implements Listener +{ + + private static final int RECALL_TIME = 5000; + private static final double PARTICLE_HEIGHT = 2.5; + private static final double PARTICLE_RADIUS = 1.5; + + private final Moba _host; + + private final Set _sessions; + + public Recall(Moba host) + { + _host = host; + + _sessions = new HashSet<>(); + } + + @EventHandler + public void interactBed(PlayerInteractEvent event) + { + if (event.isCancelled()) + { + return; + } + + if (!UtilEvent.isAction(event, ActionType.R)) + { + return; + } + + Player player = event.getPlayer(); + ItemStack itemStack = player.getItemInHand(); + + if (itemStack == null || itemStack.getType() != Material.BED || getSession(player) != null) + { + return; + } + + if (Recharge.Instance.use(player, "Recall", RECALL_TIME, false, true)) + { + _sessions.add(new RecallSession(player)); + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTER) + { + return; + } + + long now = System.currentTimeMillis(); + + for (Player player : _host.GetPlayers(true)) + { + RecallSession session = getSession(player); + + if (session == null) + { + continue; + } + + if (UtilTime.elapsed(session.Start, RECALL_TIME)) + { + _host.GetTeam(player).SpawnTeleport(player); + removeSession(player, null); + } + else if (UtilMath.offsetSquared(player.getLocation(), session.Location) > 4) + { + removeSession(player, "You moved!"); + } + else + { + Location location = session.Location.clone(); + double height = (double) (now - session.Start) / (double) RECALL_TIME; + + for (double theta = 0; theta < 2 * Math.PI; theta += Math.PI / 10) + { + double x = PARTICLE_RADIUS * Math.sin(theta); + double z = PARTICLE_RADIUS * Math.cos(theta); + + for (double y = 0.25; y < height * PARTICLE_HEIGHT; y += 0.5) + { + location.add(x, y, z); + + UtilParticle.PlayParticleToAll(ParticleType.HAPPY_VILLAGER, location, 0, 0, 0, 0.1F, 1, ViewDist.LONG); + + location.subtract(x, y, z); + } + } + } + } + } + + @EventHandler + public void damage(CustomDamageEvent event) + { + if (event.GetDamageePlayer() == null) + { + return; + } + + removeSession(event.GetDamageePlayer(), "You took damage!"); + } + + private void removeSession(Player player, String reason) + { + boolean had = _sessions.removeIf(session -> session.Player.equals(player)); + + if (had && reason != null) + { + player.sendMessage(F.main("Game", reason + " You recall has been cancelled")); + } + } + + private RecallSession getSession(Player player) + { + for (RecallSession session : _sessions) + { + if (session.Player.equals(player)) + { + return session; + } + } + + return null; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/RecallSession.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/RecallSession.java new file mode 100644 index 000000000..0abca7401 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/recall/RecallSession.java @@ -0,0 +1,19 @@ +package nautilus.game.arcade.game.games.moba.recall; + +import org.bukkit.Location; +import org.bukkit.entity.Player; + +class RecallSession +{ + + public Player Player; + public long Start; + public Location Location; + + public RecallSession(Player player) + { + Player = player; + Start = System.currentTimeMillis(); + Location = player.getLocation(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItem.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItem.java new file mode 100644 index 000000000..a4f9f78ac --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItem.java @@ -0,0 +1,66 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.leaderboard.Leaderboard; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MobaItem +{ + + private final ItemStack _item; + private final int _cost; + private List _effects; + + public MobaItem(ItemStack item, int cost) + { + _item = item; + _cost = cost; + } + + public MobaItem addEffects(MobaItemEffect... effects) + { + if (_effects == null) + { + _effects = new ArrayList<>(effects.length); + } + + Collections.addAll(_effects, effects); + return this; + } + + public ItemStack getItem() + { + ItemBuilder builder = new ItemBuilder(_item).setUnbreakable(true); + + if (getEffects() != null) + { + builder.addLore("", C.cWhite + "Effects:"); + + for (MobaItemEffect effect : getEffects()) + { + builder.addLore(" - " + effect.getDescription()); + } + + builder.addLore(""); + } + + return builder.build(); + } + + public int getCost() + { + return _cost; + } + + public List getEffects() + { + return _effects; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItemEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItemEffect.java new file mode 100644 index 000000000..3e37e1cc4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaItemEffect.java @@ -0,0 +1,67 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import mineplex.minecraft.game.core.condition.events.ConditionApplyEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.events.PlayerGameRespawnEvent; +import nautilus.game.arcade.game.games.moba.kit.hp.MobaHPRegenEvent; +import nautilus.game.arcade.game.games.moba.kit.AmmoGiveEvent; +import nautilus.game.arcade.game.games.moba.kit.CooldownCalculateEvent; +import org.bukkit.entity.Player; + +import java.text.DecimalFormat; + +public abstract class MobaItemEffect +{ + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.#"); + + protected static String format(double d) + { + return DECIMAL_FORMAT.format(d); + } + + protected static String format(ConditionType conditionType, int multi) + { + String condition = conditionType.toString().toLowerCase(); + char first = Character.toUpperCase(condition.charAt(0)); + condition = first + condition.substring(1); + + return condition + (multi == -1 ? "" : " " + (multi + 1)); + } + + protected void onAmmoGive(AmmoGiveEvent event) + { + } + + protected void onCooldownCheck(CooldownCalculateEvent event) + { + } + + protected void onDamage(CustomDamageEvent event) + { + } + + protected void onDeath(Player killed, Player killer) + { + } + + protected void onHPRegen(MobaHPRegenEvent event) + { + } + + protected void onHPRegenOthers(MobaHPRegenEvent event) + { + } + + protected void onRespawn(PlayerGameRespawnEvent event) + { + } + + protected void onCondition(ConditionApplyEvent event) + { + } + + public abstract String getDescription(); + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShop.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShop.java new file mode 100644 index 000000000..7300d7385 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShop.java @@ -0,0 +1,526 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilEnt; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.combat.CombatComponent; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; +import mineplex.minecraft.game.core.condition.events.ConditionApplyEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.events.PlayerGameRespawnEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaPlayer; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.kit.AmmoGiveEvent; +import nautilus.game.arcade.game.games.moba.kit.CooldownCalculateEvent; +import nautilus.game.arcade.game.games.moba.kit.hp.MobaHPRegenEvent; +import nautilus.game.arcade.game.games.moba.shop.assassin.MobaAssassinShop; +import nautilus.game.arcade.game.games.moba.shop.hunter.MobaHunterShop; +import nautilus.game.arcade.game.games.moba.shop.mage.MobaMageShop; +import nautilus.game.arcade.game.games.moba.shop.warrior.MobaWarriorShop; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Villager.Profession; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class MobaShop implements Listener +{ + + private final Moba _host; + private final Map _entities; + private final Map _roleMenus; + private final Map> _upgrades; + + public MobaShop(Moba host) + { + _host = host; + _entities = new HashMap<>(2); + _roleMenus = new HashMap<>(4); + _upgrades = new HashMap<>(); + + // Create menus + _roleMenus.put(MobaRole.ASSASSIN, new MobaAssassinShop(host, this)); + _roleMenus.put(MobaRole.WARRIOR, new MobaWarriorShop(host, this)); + _roleMenus.put(MobaRole.HUNTER, new MobaHunterShop(host, this)); + _roleMenus.put(MobaRole.MAGE, new MobaMageShop(host, this)); + } + + @EventHandler + public void spawnNpc(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + List locations = _host.WorldData.GetDataLocs(MobaConstants.SHOP); + + _host.CreatureAllowOverride = true; + for (Location location : locations) + { + Villager villager = location.getWorld().spawn(location, Villager.class); + + villager.setProfession(Profession.LIBRARIAN); + villager.setAgeLock(true); + villager.setRemoveWhenFarAway(false); + villager.setCustomName(C.cGoldB + "GOLD UPGRADES"); + villager.setCustomNameVisible(true); + UtilEnt.vegetate(villager); + UtilEnt.silence(villager, true); + UtilEnt.CreatureForceLook(villager, 0, UtilAlg.GetYaw(UtilAlg.getTrajectory(villager.getLocation(), _host.GetSpectatorLocation()))); + ((CraftLivingEntity) villager).getHandle().k = false; + + _entities.put(villager, location); + } + _host.CreatureAllowOverride = false; + } + + public void openShop(MobaPlayer player) + { + if (_host.GetState() != GameState.Live) + { + return; + } + + MobaShopMenu menu = _roleMenus.get(player.getRole()); + + if (menu == null) + { + player.getPlayer().sendMessage(F.main("Game", "There isn't an upgrade shop for that kit yet.")); + return; + } + + menu.open(player.getPlayer()); + } + + @EventHandler + public void npcMove(UpdateEvent event) + { + if (event.getType() != UpdateType.FASTEST) + { + return; + } + + for (Entry entry : _entities.entrySet()) + { + LivingEntity entity = entry.getKey(); + Location location = entry.getValue(); + + ((CraftLivingEntity) entity).getHandle().setPosition(location.getX(), location.getY(), location.getZ()); + } + } + + @EventHandler + public void npcDamage(CustomDamageEvent event) + { + for (LivingEntity entity : _entities.keySet()) + { + if (entity.equals(event.GetDamageeEntity())) + { + entity.setFireTicks(0); + event.SetCancelled("Shop NPC"); + return; + } + } + } + + @EventHandler + public void entityDamage(EntityDamageByEntityEvent event) + { + npcInteract(event.getEntity(), event.getDamager()); + } + + @EventHandler + public void entityInteract(PlayerInteractAtEntityEvent event) + { + npcInteract(event.getRightClicked(), event.getPlayer()); + } + + private void npcInteract(Entity clicked, Entity clicker) + { + if (!(clicker instanceof Player) || UtilPlayer.isSpectator(clicker)) + { + return; + } + + Player player = (Player) clicker; + + for (LivingEntity shop : _entities.keySet()) + { + if (clicked.equals(shop)) + { + MobaPlayer data = _host.getMobaData(player); + + if (data == null) + { + player.sendMessage(F.main("Game", "You don't appear to have any data?")); + return; + } + + openShop(data); + return; + } + } + } + + public void purchaseItem(Player player, MobaItem item) + { + List owned = _upgrades.get(player); + MobaShopCategory category = getCategory(item); + + if (category == null) + { + return; + } + + if (!category.isAllowingMultiple()) + { + owned.removeIf(previousItem -> getCategory(previousItem) == category); + } + + player.sendMessage(F.main("Game", "Purchased " + F.greenElem(item.getItem().getItemMeta().getDisplayName()) + ".")); + _host.getGoldManager().removeGold(player, item.getCost()); + owned.add(item); + + // The respawn event needs to be called here so that effects like "Total Health Increase" will work straight away, instead of after the next respawn, + // Prevents infinite speed + player.setWalkSpeed(0.2F); + player.setMaxHealth(20); + + PlayerGameRespawnEvent fakeEvent = new PlayerGameRespawnEvent(null, player); + + for (MobaItem ownedItem : owned) + { + if (ownedItem.getEffects() != null) + { + ownedItem.getEffects().forEach(effect -> effect.onRespawn(fakeEvent)); + } + } + + _host.GetKit(player).ApplyKit(player); + } + + public boolean ownsItem(Player player, MobaItem item) + { + return _upgrades.get(player).contains(item); + } + + public List getOwnedItems(Player player) + { + return _upgrades.get(player); + } + + private MobaShopCategory getCategory(MobaItem item) + { + for (MobaShopMenu menu : _roleMenus.values()) + { + for (MobaShopCategory category : menu.getCategories()) + { + if (category.getItems().contains(item)) + { + return category; + } + } + } + + return null; + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + List owned = _upgrades.get(event.getEntity()); + + owned.removeIf(item -> + { + MobaShopCategory category = getCategory(item); + + return category == null || category.isDroppingOnDeath(); + }); + } + + /* + Allow players to access the shop through an item + */ + + @EventHandler + public void interactShopItem(PlayerInteractEvent event) + { + if (event.getItem() == null || event.getItem().getType() != Material.GOLD_INGOT) + { + return; + } + + MobaPlayer mobaPlayer = _host.getMobaData(event.getPlayer()); + + if (mobaPlayer == null) + { + return; + } + + openShop(mobaPlayer); + } + + /* + Remove empty potions + */ + @EventHandler + public void removeEmptyPotions(PlayerItemConsumeEvent event) + { + if (event.getItem().getType() == Material.POTION) + { + _host.getArcadeManager().runSyncLater(() -> event.getPlayer().setItemInHand(null), 1); + } + } + + /* + Handle MobaItem events + */ + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (Player player : _host.GetPlayers(true)) + { + _upgrades.put(player, new ArrayList<>()); + } + } + + @EventHandler + public void ammoGive(AmmoGiveEvent event) + { + Player player = event.getPlayer(); + List items = _upgrades.get(player); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onAmmoGive(event); + } + } + } + + @EventHandler + public void cooldownCheck(CooldownCalculateEvent event) + { + Player player = event.getPlayer(); + List items = _upgrades.get(player); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onCooldownCheck(event); + } + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void damage(CustomDamageEvent event) + { + if (event.isCancelled()) + { + return; + } + + Player damagee = event.GetDamageePlayer(); + Player damager = event.GetDamagerPlayer(true); + + if (damagee == null || damager == null) + { + return; + } + + List items = _upgrades.get(damager); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onDamage(event); + } + } + } + + + @EventHandler + public void combatDeath(CombatDeathEvent event) + { + CombatComponent component = event.GetLog().GetKiller(); + + if (component == null || !component.IsPlayer() || !(event.GetEvent().getEntity() instanceof Player)) + { + return; + } + + Player killed = (Player) event.GetEvent().getEntity(); + Player killer = UtilPlayer.searchExact(component.getUniqueIdOfEntity()); + + if (killer == null) + { + return; + } + + List items = _upgrades.get(killer); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onDeath(killed, killer); + } + } + } + + @EventHandler + public void hpRegeneration(MobaHPRegenEvent event) + { + Player player = event.getPlayer(); + List items = _upgrades.get(player); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onHPRegen(event); + } + } + } + + @EventHandler + public void hpOther(MobaHPRegenEvent event) + { + if (event.getSource() == null) + { + return; + } + + List items = _upgrades.get(event.getSource()); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onHPRegenOthers(event); + } + } + } + + @EventHandler + public void repawn(PlayerGameRespawnEvent event) + { + Player player = event.GetPlayer(); + List items = _upgrades.get(player); + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onRespawn(event); + } + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void conditionApply(ConditionApplyEvent event) + { + if (event.isCancelled()) + { + return; + } + + LivingEntity entity = event.GetCondition().GetEnt(); + + if (!(entity instanceof Player)) + { + return; + } + + Player player = (Player) entity; + List items = _upgrades.get(player); + + if (items == null) + { + return; + } + + for (MobaItem item : items) + { + if (item.getEffects() == null) + { + continue; + } + + for (MobaItemEffect effect : item.getEffects()) + { + effect.onCondition(event); + } + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategory.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategory.java new file mode 100644 index 000000000..a01eecac1 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategory.java @@ -0,0 +1,72 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class MobaShopCategory +{ + + private final String _name; + private final List _items; + private final ItemStack _menuItem; + private boolean _dropOnDeath; + private boolean _allowMultiple; + private boolean _trackPurchases; + + public MobaShopCategory(String name, List items, ItemStack menuItem) + { + _name = name; + _items = items; + _menuItem = menuItem; + _trackPurchases = true; + } + + public String getName() + { + return _name; + } + + public List getItems() + { + return _items; + } + + public ItemStack getMenuItem() + { + return _menuItem; + } + + public MobaShopCategory dropOnDeath() + { + _dropOnDeath = true; + return this; + } + + public boolean isDroppingOnDeath() + { + return _dropOnDeath; + } + + public MobaShopCategory allowMultiple() + { + _allowMultiple = true; + return this; + } + + public boolean isAllowingMultiple() + { + return _allowMultiple; + } + + public MobaShopCategory dontTrackPurchases() + { + _trackPurchases = false; + return this; + } + + public boolean isTrackingPurchases() + { + return _trackPurchases; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategoryMenu.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategoryMenu.java new file mode 100644 index 000000000..66c061c14 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopCategoryMenu.java @@ -0,0 +1,131 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.menu.Button; +import mineplex.core.menu.Menu; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; + +public class MobaShopCategoryMenu extends Menu +{ + + private static final int SLOTS = 27; + private static final int STARTING_SLOT = 10; + private static final ItemStack GO_BACK_ITEM = new ItemBuilder(Material.BED) + .setTitle(C.cGreen + "Go Back") + .build(); + + private final Moba _host; + private final MobaShop _shop; + private final MobaShopCategory _category; + + public MobaShopCategoryMenu(Moba host, MobaShop shop, MobaShopCategory category, ArcadeManager plugin) + { + super(category.getName() + " Category", plugin); + + _host = host; + _shop = shop; + _category = category; + } + + @Override + protected Button[] setUp(Player player) + { + Button[] buttons = new Button[SLOTS]; + int slot = STARTING_SLOT; + + buttons[4] = new GoBackButton(getPlugin()); + + for (MobaItem item : _category.getItems()) + { + ItemBuilder builder = new ItemBuilder(item.getItem()); + boolean owns = _shop.ownsItem(player, item) && _category.isTrackingPurchases(); + boolean canPurchase = _host.getGoldManager().hasGold(player, item.getCost()); + int gold = _host.getGoldManager().getGold(player); + + builder.setTitle((canPurchase ? C.cGreen : C.cRed) + item.getItem().getItemMeta().getDisplayName()); + + if (owns) + { + builder.setType(Material.WOOL); + builder.setData((byte) 5); + builder.addLore(C.cRed + "You already have purchased this upgrade."); + } + else + { + builder.addLore(C.cWhite + "Cost: " + C.cGold + item.getCost(), C.cWhite + "Your Gold: " + C.cGold + gold, ""); + + if (canPurchase) + { + builder.addLore(C.cGreen + "Click to purchase."); + } + else + { + builder.addLore(C.cRed + "You cannot afford this item."); + } + } + + buttons[slot++] = new MobaPurchaseButton(builder.build(), getPlugin(), item); + + // Reached the end of the row, wrap it to keep it neat. + if (slot == 17) + { + slot = 19; + } + } + + return buttons; + } + + class MobaPurchaseButton extends Button + { + + private MobaItem _item; + + public MobaPurchaseButton(ItemStack itemStack, ArcadeManager plugin, MobaItem item) + { + super(itemStack, plugin); + + _item = item; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + boolean owns = _shop.ownsItem(player, _item) && _category.isTrackingPurchases(); + boolean canPurchase = _host.getGoldManager().hasGold(player, _item.getCost()); + + if (!owns && canPurchase) + { + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1.6F); + _shop.purchaseItem(player, _item); + player.closeInventory(); + } + else + { + player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1, 0.6F); + } + } + } + + class GoBackButton extends Button + { + + public GoBackButton(ArcadeManager plugin) + { + super(GO_BACK_ITEM, plugin); + } + + @Override + public void onClick(Player player, ClickType clickType) + { + _shop.openShop(_host.getMobaData(player)); + } + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopMenu.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopMenu.java new file mode 100644 index 000000000..bc60eba4a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/MobaShopMenu.java @@ -0,0 +1,159 @@ +package nautilus.game.arcade.game.games.moba.shop; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilUI; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.core.menu.Button; +import mineplex.core.menu.Menu; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MobaShopMenu extends Menu +{ + + private static final MobaShopCategory CONSUMABLES = new MobaShopCategory("Consumables", Arrays.asList( + new MobaItem(new ItemBuilder(Material.POTION) + .setTitle(C.cGreenB + "Small Health Potion") + .addPotionEffect(new PotionEffect(PotionEffectType.HEAL, 1, 0)) + .build(), 100), + new MobaItem(new ItemBuilder(Material.POTION) + .setTitle(C.cYellowB + "Large Health Potion") + .addPotionEffect(new PotionEffect(PotionEffectType.HEAL, 1, 1)) + .build(), 200), + new MobaItem(new ItemBuilder(Material.POTION) + .setTitle(C.cYellowB + "Power Potion") + .addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 90 * 20, 0)) + .build(), 1000), + new MobaItem(new ItemBuilder(Material.POTION) + .setTitle(C.cYellowB + "Speed Potion") + .addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 180 * 20, 0)) + .build(), 500), + new MobaItem(new ItemBuilder(Material.ENDER_PEARL) + .setTitle(C.cYellowB + "Ender Pearl") + .build(), 750) + ), new ItemStack(Material.POTION)).dropOnDeath().allowMultiple().dontTrackPurchases(); + private static final int SLOTS = 27; + + private final Moba _host; + private final MobaShop _shop; + private final List _categories; + + public MobaShopMenu(Moba host, MobaShop shop, MobaRole role) + { + super(role.getName() + " Upgrade Shop", host.getArcadeManager()); + + _host = host; + _shop = shop; + _categories = new ArrayList<>(); + } + + protected void addCategory(MobaShopCategory category) + { + _categories.add(category); + } + + protected void addConsumables() + { + _categories.add(CONSUMABLES); + } + + @Override + protected Button[] setUp(Player player) + { + Button[] buttons = new Button[SLOTS]; + int[] slots = UtilUI.getIndicesFor(_categories.size(), 1); + int slot = 0; + + for (MobaShopCategory category : _categories) + { + ItemBuilder builder; + MobaItem owned = null; + + for (MobaItem item : category.getItems()) + { + if (_shop.ownsItem(player, item)) + { + owned = item; + break; + } + } + + if (owned == null) + { + builder = new ItemBuilder(category.getMenuItem()); + } + else + { + builder = new ItemBuilder(owned.getItem()); + } + + builder.setTitle(C.cGreen + category.getName()); + builder.addLore(""); + + if (category.isAllowingMultiple()) + { + builder.addLore(C.cWhite + "Current Upgrades:"); + boolean ownsAtLeastOne = false; + + for (MobaItem item : category.getItems()) + { + if (_shop.ownsItem(player, item)) + { + ownsAtLeastOne = true; + builder.addLore(" - " + item.getItem().getItemMeta().getDisplayName()); + } + } + + if (!ownsAtLeastOne) + { + builder.addLore(" - None"); + } + } + else + { + builder.addLore(C.cWhite + "Current Upgrade: " + (owned == null ? C.cGray + "None" : owned.getItem().getItemMeta().getDisplayName())); + } + + builder.addLore("", C.cYellow + "Click to view the upgrades."); + + buttons[slots[slot++]] = new MobaCategoryButton(builder.build(), getPlugin(), category); + } + + return buttons; + } + + class MobaCategoryButton extends Button + { + + private MobaShopCategory _category; + + public MobaCategoryButton(ItemStack itemStack, ArcadeManager plugin, MobaShopCategory category) + { + super(itemStack, plugin); + + _category = category; + } + + @Override + public void onClick(Player player, ClickType clickType) + { + new MobaShopCategoryMenu(_host, _shop, _category, getPlugin()).open(player); + } + } + + public List getCategories() + { + return _categories; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/assassin/MobaAssassinShop.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/assassin/MobaAssassinShop.java new file mode 100644 index 000000000..96c28be81 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/assassin/MobaAssassinShop.java @@ -0,0 +1,132 @@ +package nautilus.game.arcade.game.games.moba.shop.assassin; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import nautilus.game.arcade.game.games.moba.shop.MobaShop; +import nautilus.game.arcade.game.games.moba.shop.MobaShopCategory; +import nautilus.game.arcade.game.games.moba.shop.MobaShopMenu; +import nautilus.game.arcade.game.games.moba.shop.effects.*; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class MobaAssassinShop extends MobaShopMenu +{ + + private static final MobaShopCategory SWORD = new MobaShopCategory("Sword", Arrays.asList( + new MobaItem(new ItemBuilder(Material.GOLD_SWORD) + .setTitle(C.cGreenB + "Sword of Time") + .build(), 800) + .addEffects( + new MobaKillHealEffect(3) + ), + new MobaItem(new ItemBuilder(Material.IRON_SWORD) + .setTitle(C.cYellowB + "Adventurer's Sword") + .build(), 1000), + new MobaItem(new ItemBuilder(Material.DIAMOND_SWORD) + .setTitle(C.cDRedB + "Pumpkin King's Blade") + .addEnchantment(Enchantment.DAMAGE_ALL, 3) + .build(), 1750) + ), new ItemStack(Material.WOOD_SWORD)); + + private static final MobaShopCategory HELMET = new MobaShopCategory("Helmet", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Leather Cap") + .build(), 200), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Ninja's Mask") + .build(), 500) + .addEffects( + new MobaKillHealEffect(2) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Urchin's Cap") + .build(), 600) + .addEffects( + new MobaHPRegenEffect(0.2) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_HELMET) + .setTitle(C.cYellow + "Bruiser's Helm") + .build(), 1000) + ), new ItemStack(Material.LEATHER_HELMET)); + + private static final MobaShopCategory CHESTPLATE = new MobaShopCategory("Chestplate", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Leather Chestplate") + .build(), 250), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Ninja's Chestcloth") + .build(), 750) + .addEffects( + new MobaCDREffect(0.15) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Urchin's Chestcloth") + .build(), 850) + .addEffects( + new MobaMeleeDamageEffect("Urchin's Chestcloth", 1) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_CHESTPLATE) + .setTitle(C.cYellow + "Bruiser's Chestplate") + .build(), 1250) + ), new ItemStack(Material.LEATHER_CHESTPLATE)); + + private static final MobaShopCategory LEGGINGS = new MobaShopCategory("Leggings", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Leather Leggings") + .build(), 250), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Ninja's Leggings") + .build(), 750) + .addEffects( + new MobaCDREffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Urchin's Leggings") + .build(), 850) + .addEffects( + new MobaAbilityDamageEffect("Urchin's Leggings", 0.1) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_LEGGINGS) + .setTitle(C.cYellow + "Bruiser's Leggings") + .build(), 1250) + ), new ItemStack(Material.LEATHER_LEGGINGS)); + + private static final MobaShopCategory BOOTS = new MobaShopCategory("Boots", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Leather Boots") + .build(), 200), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Ninja's Boots") + .build(), 500) + .addEffects( + new MobaSpeedEffect(0.15) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Urchin's Boots") + .build(), 600) + .addEffects( + new MobaSpeedEffect(0.17) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_BOOTS) + .setTitle(C.cYellow + "Bruiser's Boots") + .build(), 1000) + ), new ItemStack(Material.LEATHER_BOOTS)); + + public MobaAssassinShop(Moba host, MobaShop shop) + { + super(host, shop, MobaRole.ASSASSIN); + + addCategory(SWORD); + addCategory(HELMET); + addCategory(CHESTPLATE); + addCategory(LEGGINGS); + addCategory(BOOTS); + addConsumables(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAbilityDamageEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAbilityDamageEffect.java new file mode 100644 index 000000000..63d15b7df --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAbilityDamageEffect.java @@ -0,0 +1,49 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.kit.hp.MobaHPRegenEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +public class MobaAbilityDamageEffect extends MobaItemEffect +{ + + private String _reason; + private double _factor; + + public MobaAbilityDamageEffect(String reason, double factor) + { + _reason = reason; + _factor = factor; + } + + @Override + protected void onDamage(CustomDamageEvent event) + { + if (event.GetCause() != DamageCause.CUSTOM || event.GetReason().contains(MobaConstants.BASIC_ATTACK)) + { + return; + } + + event.AddMod(_reason, event.GetDamage() * _factor); + } + + @Override + protected void onHPRegenOthers(MobaHPRegenEvent event) + { + if (event.isNatural()) + { + return; + } + + event.increaseHealth(_factor); + } + + @Override + public String getDescription() + { + return "Increases ability damage/healing by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAmmoIncreaseEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAmmoIncreaseEffect.java new file mode 100644 index 000000000..c62f9d935 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaAmmoIncreaseEffect.java @@ -0,0 +1,28 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import nautilus.game.arcade.game.games.moba.kit.AmmoGiveEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; + +public class MobaAmmoIncreaseEffect extends MobaItemEffect +{ + + private int _maxAmmoIncrease; + + public MobaAmmoIncreaseEffect(int maxAmmoIncrease) + { + _maxAmmoIncrease = maxAmmoIncrease; + } + + @Override + protected void onAmmoGive(AmmoGiveEvent event) + { + event.setMaxAmmo(event.getMaxAmmo() + _maxAmmoIncrease); + } + + @Override + public String getDescription() + { + return "Increases max ammo by " + F.greenElem(format(_maxAmmoIncrease)) + "."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaBasicAttackDamageEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaBasicAttackDamageEffect.java new file mode 100644 index 000000000..3f19d483c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaBasicAttackDamageEffect.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; + +public class MobaBasicAttackDamageEffect extends MobaItemEffect +{ + + private String _reason; + private double _factor; + + public MobaBasicAttackDamageEffect(String reason, double factor) + { + _reason = reason; + _factor = factor; + } + + @Override + protected void onDamage(CustomDamageEvent event) + { + if (!event.GetReason().contains(MobaConstants.BASIC_ATTACK)) + { + return; + } + + event.AddMod(_reason, event.GetDamage() * _factor); + } + + @Override + public String getDescription() + { + return "Increases basic attack damage by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDRAmmoEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDRAmmoEffect.java new file mode 100644 index 000000000..ab0269862 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDRAmmoEffect.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import nautilus.game.arcade.game.games.moba.kit.CooldownCalculateEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; + +public class MobaCDRAmmoEffect extends MobaItemEffect +{ + + private double _factor; + + public MobaCDRAmmoEffect(double factor) + { + _factor = factor; + } + + @Override + public void onCooldownCheck(CooldownCalculateEvent event) + { + if (!event.getAbility().equals(MobaConstants.AMMO)) + { + return; + } + + event.decreaseCooldown(_factor); + } + + @Override + public String getDescription() + { + return "Decreases ammo reload time by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDREffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDREffect.java new file mode 100644 index 000000000..a141f2a3a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaCDREffect.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import nautilus.game.arcade.game.games.moba.kit.CooldownCalculateEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import nautilus.game.arcade.game.games.moba.util.MobaConstants; + +public class MobaCDREffect extends MobaItemEffect +{ + + private double _factor; + + public MobaCDREffect(double factor) + { + _factor = factor; + } + + @Override + public void onCooldownCheck(CooldownCalculateEvent event) + { + if (event.getAbility().equals(MobaConstants.AMMO)) + { + return; + } + + event.decreaseCooldown(_factor); + } + + @Override + public String getDescription() + { + return "Decreases ability cooldowns by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaConditionImmunityEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaConditionImmunityEffect.java new file mode 100644 index 000000000..d79a5e76c --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaConditionImmunityEffect.java @@ -0,0 +1,32 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import mineplex.minecraft.game.core.condition.events.ConditionApplyEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; + +public class MobaConditionImmunityEffect extends MobaItemEffect +{ + + private ConditionType _conditionType; + + public MobaConditionImmunityEffect(ConditionType conditionType) + { + _conditionType = conditionType; + } + + @Override + protected void onCondition(ConditionApplyEvent event) + { + if (event.GetCondition().GetType() == _conditionType) + { + event.setCancelled(true); + } + } + + @Override + public String getDescription() + { + return "Grants immunity to " + F.greenElem(format(_conditionType, -1)) + " effects."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHPRegenEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHPRegenEffect.java new file mode 100644 index 000000000..0489fe986 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHPRegenEffect.java @@ -0,0 +1,28 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import nautilus.game.arcade.game.games.moba.kit.hp.MobaHPRegenEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; + +public class MobaHPRegenEffect extends MobaItemEffect +{ + + private double _factor; + + public MobaHPRegenEffect(double factor) + { + _factor = factor; + } + + @Override + public void onHPRegen(MobaHPRegenEvent event) + { + event.increaseHealth(_factor); + } + + @Override + public String getDescription() + { + return "Increases HP regeneration by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowAmmoEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowAmmoEffect.java new file mode 100644 index 000000000..791794fc2 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowAmmoEffect.java @@ -0,0 +1,36 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.Managers; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.HeroKit; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Player; + +public class MobaHitArrowAmmoEffect extends MobaItemEffect +{ + + @Override + protected void onDamage(CustomDamageEvent event) + { + if (!(event.GetProjectile() instanceof Arrow)) + { + return; + } + + Player damager = event.GetDamagerPlayer(true); + + Moba host = (Moba) Managers.get(ArcadeManager.class).GetGame(); + HeroKit kit = host.getMobaData(damager).getKit(); + + kit.giveAmmo(damager, 1); + } + + @Override + public String getDescription() + { + return "Hitting a player with an arrow gives you a new arrow."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowHealEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowHealEffect.java new file mode 100644 index 000000000..f5e22be7a --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitArrowHealEffect.java @@ -0,0 +1,37 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Player; + +public class MobaHitArrowHealEffect extends MobaItemEffect +{ + + private double _factor; + + public MobaHitArrowHealEffect(double factor) + { + _factor = factor; + } + + @Override + protected void onDamage(CustomDamageEvent event) + { + if (!(event.GetProjectile() instanceof Arrow)) + { + return; + } + + Player damager = event.GetDamagerPlayer(true); + + damager.setHealth(Math.min(damager.getMaxHealth(), damager.getHealth() + (event.GetDamage() * _factor))); + } + + @Override + public String getDescription() + { + return "Hitting a player with an arrow heals for " + F.greenElem(format(_factor * 100)) + "% of the damage."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitConditionEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitConditionEffect.java new file mode 100644 index 000000000..60095e421 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaHitConditionEffect.java @@ -0,0 +1,56 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.Managers; +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.condition.Condition; +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import mineplex.minecraft.game.core.condition.ConditionManager; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.ArcadeManager; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +public class MobaHitConditionEffect extends MobaItemEffect +{ + + private String _reason; + private ConditionType _conditionType; + private double _duration; + private int _multi; + private boolean _applyToDamagee; + + public MobaHitConditionEffect(String reason, ConditionType conditionType, double duration, int multi, boolean applyToDamagee) + { + _reason = reason; + _conditionType = conditionType; + _duration = duration; + _multi = multi; + _applyToDamagee = applyToDamagee; + } + + @Override + protected void onDamage(CustomDamageEvent event) + { + Player damagee = event.GetDamageePlayer(); + Player damager = event.GetDamagerPlayer(true); + + if (!_applyToDamagee) + { + // Swap damagee and damager + Player temp = damagee; + damagee = damager; + damager = temp; + } + + ConditionManager conditionManager = Managers.get(ArcadeManager.class).GetCondition(); + + conditionManager.AddCondition(new Condition(conditionManager, _reason, damagee, damager, _conditionType, _multi, (int) (_duration * 20), false, Material.WEB, (byte) 0, true, false)); + } + + @Override + public String getDescription() + { + return "Hitting a player gives " + (_applyToDamagee ? "them" : "you") + " " + F.greenElem(format(_conditionType, _multi)) + " for " + F.time(format(_duration)) + " seconds."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaKillHealEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaKillHealEffect.java new file mode 100644 index 000000000..0565ef5e5 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaKillHealEffect.java @@ -0,0 +1,30 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.entity.Player; + +public class MobaKillHealEffect extends MobaItemEffect +{ + + private double _health; + + public MobaKillHealEffect(double health) + { + _health = health; + } + + @Override + public void onDeath(Player killed, Player killer) + { + MobaUtil.heal(killer, killer, _health); + } + + @Override + public String getDescription() + { + return "Killing a player heals for an additional " + F.greenElem(format(_health / 2)) + C.cRed + "❤" + C.cGray + "."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaMeleeDamageEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaMeleeDamageEffect.java new file mode 100644 index 000000000..8e2e348bc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaMeleeDamageEffect.java @@ -0,0 +1,31 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; + +public class MobaMeleeDamageEffect extends MobaItemEffect +{ + + private String _reason; + private double _increase; + + public MobaMeleeDamageEffect(String reason, double increase) + { + _reason = reason; + _increase = increase; + } + + @Override + protected void onDamage(CustomDamageEvent event) + { + event.AddMod(_reason, _increase); + } + + @Override + public String getDescription() + { + return "All your melee attacks deal " + F.greenElem("+" + format(_increase / 2)) + C.cRed + "❤" + C.cGray + "."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaSpeedEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaSpeedEffect.java new file mode 100644 index 000000000..15d7d7196 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaSpeedEffect.java @@ -0,0 +1,31 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.F; +import nautilus.game.arcade.events.PlayerGameRespawnEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import org.bukkit.entity.Player; + +public class MobaSpeedEffect extends MobaItemEffect +{ + + private double _factor; + + public MobaSpeedEffect(double factor) + { + _factor = factor; + } + + @Override + public void onRespawn(PlayerGameRespawnEvent event) + { + Player player = event.GetPlayer(); + + player.setWalkSpeed((float) (player.getWalkSpeed() + (player.getWalkSpeed() * _factor))); + } + + @Override + public String getDescription() + { + return "Increases movement speed by " + F.greenElem(format(_factor * 100)) + "%."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaTotalHealthEffect.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaTotalHealthEffect.java new file mode 100644 index 000000000..80af5c495 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/effects/MobaTotalHealthEffect.java @@ -0,0 +1,33 @@ +package nautilus.game.arcade.game.games.moba.shop.effects; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import nautilus.game.arcade.events.PlayerGameRespawnEvent; +import nautilus.game.arcade.game.games.moba.shop.MobaItemEffect; +import org.bukkit.entity.Player; + +public class MobaTotalHealthEffect extends MobaItemEffect +{ + + private int _health; + + public MobaTotalHealthEffect(int health) + { + _health = health; + } + + @Override + public void onRespawn(PlayerGameRespawnEvent event) + { + Player player = event.GetPlayer(); + + player.setMaxHealth(player.getMaxHealth() + _health); + player.setHealth(player.getMaxHealth()); + } + + @Override + public String getDescription() + { + return "Increases total hearts by " + F.greenElem(format(_health / 2)) + C.cRed + "❤" + C.cGray + "."; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/hunter/MobaHunterShop.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/hunter/MobaHunterShop.java new file mode 100644 index 000000000..2c9b75b86 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/hunter/MobaHunterShop.java @@ -0,0 +1,208 @@ +package nautilus.game.arcade.game.games.moba.shop.hunter; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import nautilus.game.arcade.game.games.moba.shop.MobaShop; +import nautilus.game.arcade.game.games.moba.shop.MobaShopCategory; +import nautilus.game.arcade.game.games.moba.shop.MobaShopMenu; +import nautilus.game.arcade.game.games.moba.shop.effects.*; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class MobaHunterShop extends MobaShopMenu +{ + + private static final MobaShopCategory BOW = new MobaShopCategory("Bow", Arrays.asList( + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cGreenB + "Hunter's Bow") + .addEnchantment(Enchantment.ARROW_DAMAGE, 1) + .build(), 500), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cGreenB + "Elven Bow") + .addEnchantment(Enchantment.ARROW_DAMAGE, 2) + .build(), 750), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cGreenB + "Eagle's Bow") + .addEnchantment(Enchantment.ARROW_DAMAGE, 3) + .build(), 1000), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cYellowB + "Bow of Pursuit") + .addEnchantment(Enchantment.ARROW_DAMAGE, 2) + .build(), 1200) + .addEffects( + new MobaHitConditionEffect("Bow of Pursuit", ConditionType.SPEED, 3, 1, false) + ), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cYellowB + "Vampiric Bow") + .addEnchantment(Enchantment.ARROW_DAMAGE, 1) + .build(), 1500) + .addEffects( + new MobaKillHealEffect(0.15) + ), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cYellowB + "Bow of Renewal") + .addEnchantment(Enchantment.ARROW_DAMAGE, 1) + .build(), 1750) + .addEffects( + new MobaHitArrowAmmoEffect() + ), + new MobaItem(new ItemBuilder(Material.BOW) + .setTitle(C.cYellowB + "Specialist's Bow") + .build(), 1000) + .addEffects( + new MobaCDREffect(0.1), + new MobaAbilityDamageEffect("Specialist's Bow", 0.2) + ) + ), new ItemStack(Material.BOW)); + + private static final MobaShopCategory HELMET = new MobaShopCategory("Helmet", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Leather Helmet") + .build(), 200), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Leather Cap of Holding") + .build(), 400) + .addEffects( + new MobaAmmoIncreaseEffect(1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Leather Cap of Nimble Fingers") + .build(), 400) + .addEffects( + new MobaCDRAmmoEffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Focused Cap") + .build(), 500) + .addEffects( + new MobaCDREffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Vampiric Helmet") + .build(), 500) + .addEffects( + new MobaHPRegenEffect(0.2) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_HELMET) + .setTitle(C.cGreen + "Chainmail Helmet") + .build(), 500) + ), new ItemStack(Material.LEATHER_HELMET)); + + private static final MobaShopCategory CHESTPLATE = new MobaShopCategory("Chestplate", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Leather Chestplate") + .build(), 250), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Leather Chestplate of Nimble Fingers") + .build(), 750) + .addEffects( + new MobaCDRAmmoEffect(0.15) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Focused Chestplate") + .build(), 750) + .addEffects( + new MobaCDREffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Vampiric Chestplate") + .build(), 750) + .addEffects( + new MobaKillHealEffect(3) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_CHESTPLATE) + .setTitle(C.cGreen + "Chainmail Chestplate") + .build(), 500) + ), new ItemStack(Material.LEATHER_CHESTPLATE)); + + private static final MobaShopCategory LEGGINGS = new MobaShopCategory("Leggings", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Leather Leggings") + .build(), 250), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Leather Leggings of Nimble Fingers") + .build(), 750) + .addEffects( + new MobaCDRAmmoEffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Focused Leggings") + .build(), 750) + .addEffects( + new MobaCDREffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Vampiric Leggings") + .build(), 700) + .addEffects( + new MobaKillHealEffect(3) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_LEGGINGS) + .setTitle(C.cGreen + "Chainmail Leggings") + .build(), 500) + ), new ItemStack(Material.LEATHER_LEGGINGS)); + + private static final MobaShopCategory BOOTS = new MobaShopCategory("Boots", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Leather Boots") + .build(), 250), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Leather Boots of Nimble Fingers") + .build(), 400) + .addEffects( + new MobaCDRAmmoEffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Focused Boots") + .build(), 600) + .addEffects( + new MobaCDREffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Vampiric Boots") + .build(), 500) + .addEffects( + new MobaKillHealEffect(1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Leather Hiking Boots") + .build(), 300) + .addEffects( + new MobaSpeedEffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_BOOTS) + .setTitle(C.cGreen + "Leather Moccasins") + .build(), 500) + .addEffects( + new MobaSpeedEffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_BOOTS) + .setTitle(C.cGreen + "Leather Crosstrainers") + .build(), 800) + .addEffects( + new MobaSpeedEffect(0.15) + ), + new MobaItem(new ItemBuilder(Material.CHAINMAIL_BOOTS) + .setTitle(C.cGreen + "Chainmail Boots") + .build(), 500) + ), new ItemStack(Material.LEATHER_BOOTS)); + + public MobaHunterShop(Moba host, MobaShop shop) + { + super(host, shop, MobaRole.HUNTER); + + addCategory(BOW); + addCategory(HELMET); + addCategory(CHESTPLATE); + addCategory(LEGGINGS); + addCategory(BOOTS); + addConsumables(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/mage/MobaMageShop.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/mage/MobaMageShop.java new file mode 100644 index 000000000..e8b5a38b4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/mage/MobaMageShop.java @@ -0,0 +1,160 @@ +package nautilus.game.arcade.game.games.moba.shop.mage; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import nautilus.game.arcade.game.games.moba.shop.MobaShop; +import nautilus.game.arcade.game.games.moba.shop.MobaShopCategory; +import nautilus.game.arcade.game.games.moba.shop.MobaShopMenu; +import nautilus.game.arcade.game.games.moba.shop.effects.MobaAbilityDamageEffect; +import nautilus.game.arcade.game.games.moba.shop.effects.MobaBasicAttackDamageEffect; +import nautilus.game.arcade.game.games.moba.shop.effects.MobaCDREffect; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class MobaMageShop extends MobaShopMenu +{ + + // Dark Purple + private static final Color ABILITY_DAMAGE_COLOUR = Color.fromBGR(181, 7, 123); + // Purple + private static final Color COOLDOWN_COLOUR = Color.PURPLE; + // Light Purple + private static final Color BASIC_DAMAGE_COLOUR = Color.fromBGR(254, 89, 200); + + private static final MobaShopCategory HELMET = new MobaShopCategory("Helmet", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Leather Cap") + .build(), 200), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Adept's Cap") + .setColor(ABILITY_DAMAGE_COLOUR) + .build(), 750) + .addEffects( + new MobaAbilityDamageEffect("Adept's Cap", 0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Helm of Focus") + .setColor(COOLDOWN_COLOUR) + .build(), 750) + .addEffects( + new MobaCDREffect(0.03) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_HELMET) + .setTitle(C.cGreen + "Battle Mage Cap") + .setColor(BASIC_DAMAGE_COLOUR) + .build(), 750) + .addEffects( + new MobaBasicAttackDamageEffect("Battle Mage Cap", 0.03) + ), + new MobaItem(new ItemBuilder(Material.GOLD_HELMET) + .setTitle(C.cYellow + "Golden Helmet") + .build(), 1000) + ), new ItemStack(Material.LEATHER_HELMET)); + + private static final MobaShopCategory CHESTPLATE = new MobaShopCategory("Chestplate", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Leather Chestplate") + .build(), 400), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Adept's Chestplate") + .setColor(ABILITY_DAMAGE_COLOUR) + .build(), 1500) + .addEffects( + new MobaAbilityDamageEffect("Adept's Chestplate", 0.15) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Chestplate of Focus") + .setColor(COOLDOWN_COLOUR) + .build(), 1250) + .addEffects( + new MobaCDREffect(0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_CHESTPLATE) + .setTitle(C.cGreen + "Battle Mage Chestplate") + .setColor(BASIC_DAMAGE_COLOUR) + .build(), 1250) + .addEffects( + new MobaBasicAttackDamageEffect("Battle Mage Chestplate", 0.1) + ), + new MobaItem(new ItemBuilder(Material.GOLD_CHESTPLATE) + .setTitle(C.cYellow + "Golden Chestplate") + .build(), 1250) + ), new ItemStack(Material.LEATHER_CHESTPLATE)); + + private static final MobaShopCategory LEGGINGS = new MobaShopCategory("Leggings", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Leather Leggings") + .build(), 400), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Adept's Leggings") + .setColor(ABILITY_DAMAGE_COLOUR) + .build(), 1000) + .addEffects( + new MobaAbilityDamageEffect("Adept's Leggings", 0.1) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Leggings of Focus") + .setColor(COOLDOWN_COLOUR) + .build(), 1000) + .addEffects( + new MobaCDREffect(0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_LEGGINGS) + .setTitle(C.cGreen + "Battle Mage Leggings") + .setColor(BASIC_DAMAGE_COLOUR) + .build(), 1000) + .addEffects( + new MobaBasicAttackDamageEffect("Battle Mage Leggings", 0.05) + ), + new MobaItem(new ItemBuilder(Material.GOLD_LEGGINGS) + .setTitle(C.cYellow + "Golden Leggings") + .build(), 1000) + ), new ItemStack(Material.LEATHER_LEGGINGS)); + + private static final MobaShopCategory BOOTS = new MobaShopCategory("Boots", Arrays.asList( + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Leather Boots") + .build(), 200), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Adept's Boots") + .setColor(ABILITY_DAMAGE_COLOUR) + .build(), 750) + .addEffects( + new MobaAbilityDamageEffect("Adept's Boots", 0.05) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Boots of Focus") + .setColor(COOLDOWN_COLOUR) + .build(), 750) + .addEffects( + new MobaCDREffect(0.03) + ), + new MobaItem(new ItemBuilder(Material.LEATHER_BOOTS) + .setTitle(C.cGreen + "Battle Mage Boots") + .setColor(BASIC_DAMAGE_COLOUR) + .build(), 750) + .addEffects( + new MobaBasicAttackDamageEffect("Battle Mage Boots", 0.03) + ), + new MobaItem(new ItemBuilder(Material.GOLD_BOOTS) + .setTitle(C.cYellow + "Golden Boots") + .build(), 1000) + ), new ItemStack(Material.LEATHER_BOOTS)); + + public MobaMageShop(Moba host, MobaShop shop) + { + super(host, shop, MobaRole.MAGE); + + addCategory(HELMET); + addCategory(CHESTPLATE); + addCategory(LEGGINGS); + addCategory(BOOTS); + addConsumables(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/warrior/MobaWarriorShop.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/warrior/MobaWarriorShop.java new file mode 100644 index 000000000..2d0ca6f60 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/shop/warrior/MobaWarriorShop.java @@ -0,0 +1,202 @@ +package nautilus.game.arcade.game.games.moba.shop.warrior; + +import mineplex.core.common.util.C; +import mineplex.core.itemstack.ItemBuilder; +import mineplex.minecraft.game.core.condition.Condition.ConditionType; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.MobaRole; +import nautilus.game.arcade.game.games.moba.shop.MobaItem; +import nautilus.game.arcade.game.games.moba.shop.MobaShop; +import nautilus.game.arcade.game.games.moba.shop.MobaShopCategory; +import nautilus.game.arcade.game.games.moba.shop.MobaShopMenu; +import nautilus.game.arcade.game.games.moba.shop.effects.*; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; + +public class MobaWarriorShop extends MobaShopMenu +{ + + private static final MobaShopCategory SWORD = new MobaShopCategory("Sword", Arrays.asList( + new MobaItem(new ItemBuilder(Material.STONE_SWORD) + .setTitle(C.cGreenB + "Stone Sword") + .build(), 500), + new MobaItem(new ItemBuilder(Material.GOLD_SWORD) + .setTitle(C.cYellowB + "Frostbound Sword") + .build(), 750) + .addEffects( + new MobaHitConditionEffect("Frostbound Sword", ConditionType.SLOW, 3, 0, true) + ), + new MobaItem(new ItemBuilder(Material.GOLD_SWORD) + .setTitle(C.cYellowB + "Swift Blade") + .build(), 750) + .addEffects( + new MobaConditionImmunityEffect(ConditionType.SLOW) + ), + new MobaItem(new ItemBuilder(Material.IRON_SWORD) + .setTitle(C.cDRedB + "Knight's Blade") + .build(), 1250) + ), new ItemStack(Material.WOOD_SWORD)); + + private static final MobaShopCategory HELMET = new MobaShopCategory("Helmet", Arrays.asList( + new MobaItem(new ItemBuilder(Material.IRON_HELMET) + .setTitle(C.cGreenB + "Archer's Bane") + .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 1) + .build(), 400) + .addEffects( + new MobaHPRegenEffect(0.03) + ), +// new MobaItem(new ItemBuilder(Material.IRON_HELMET) +// .setTitle(C.cYellowB + "Superior Archer's Bane") +// .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 2) +// .build(), 750) +// .addEffects( +// new MobaHPRegenEffect(0.05) +// ), + new MobaItem(new ItemBuilder(Material.IRON_HELMET) + .setTitle(C.cGreenB + "Brawler's Plate") + .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build(), 400) + .addEffects( + new MobaHPRegenEffect(0.03) + ), +// new MobaItem(new ItemBuilder(Material.IRON_HELMET) +// .setTitle(C.cYellowB + "Superior Brawler's Plate") +// .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) +// .build(), 750) +// .addEffects( +// new MobaHPRegenEffect(0.05) +// ), + new MobaItem(new ItemBuilder(Material.DIAMOND_HELMET) + .setTitle(C.cDRedB + "Prince's Plate") + .build(), 2000) + .addEffects( + new MobaHPRegenEffect(0.15) + ) + ), new ItemStack(Material.IRON_HELMET)); + + private static final MobaShopCategory CHESTPLATE = new MobaShopCategory("Chestplate", Arrays.asList( + new MobaItem(new ItemBuilder(Material.IRON_CHESTPLATE) + .setTitle(C.cGreenB + "Archer's Bane") + .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 1) + .build(), 600) + .addEffects( + new MobaTotalHealthEffect(2) + ), +// new MobaItem(new ItemBuilder(Material.IRON_CHESTPLATE) +// .setTitle(C.cYellowB + "Superior Archer's Bane") +// .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 2) +// .build(), 1000) +// .addEffects( +// new MobaTotalHealthEffect(4) +// ), + new MobaItem(new ItemBuilder(Material.IRON_CHESTPLATE) + .setTitle(C.cGreenB + "Brawler's Plate") + .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build(), 600) + .addEffects( + new MobaTotalHealthEffect(2) + ), +// new MobaItem(new ItemBuilder(Material.IRON_CHESTPLATE) +// .setTitle(C.cYellowB + "Superior Brawler's Plate") +// .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) +// .build(), 1000) +// .addEffects( +// new MobaTotalHealthEffect(4) +// ), + new MobaItem(new ItemBuilder(Material.DIAMOND_CHESTPLATE) + .setTitle(C.cDRedB + "Prince's Plate") + .build(), 2500) + .addEffects( + new MobaTotalHealthEffect(4) + ) + ), new ItemStack(Material.IRON_CHESTPLATE)); + + private static final MobaShopCategory LEGGINGS = new MobaShopCategory("Leggings", Arrays.asList( + new MobaItem(new ItemBuilder(Material.IRON_LEGGINGS) + .setTitle(C.cGreenB + "Archer's Bane") + .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 1) + .build(), 600) + .addEffects( + new MobaCDREffect(0.05) + ), +// new MobaItem(new ItemBuilder(Material.IRON_LEGGINGS) +// .setTitle(C.cYellowB + "Superior Archer's Bane") +// .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 2) +// .build(), 1000) +// .addEffects( +// new MobaCDREffect(0.07) +// ), + new MobaItem(new ItemBuilder(Material.IRON_LEGGINGS) + .setTitle(C.cGreenB + "Brawler's Plate") + .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build(), 600) + .addEffects( + new MobaCDREffect(0.05) + ), +// new MobaItem(new ItemBuilder(Material.IRON_LEGGINGS) +// .setTitle(C.cYellowB + "Superior Brawler's Plate") +// .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) +// .build(), 1000) +// .addEffects( +// new MobaCDREffect(0.07) +// ), + new MobaItem(new ItemBuilder(Material.DIAMOND_LEGGINGS) + .setTitle(C.cDRedB + "Prince's Plate") + .build(), 2500) + .addEffects( + new MobaCDREffect(0.1) + ) + ), new ItemStack(Material.IRON_LEGGINGS)); + + private static final MobaShopCategory BOOTS = new MobaShopCategory("Boots", Arrays.asList( + new MobaItem(new ItemBuilder(Material.IRON_BOOTS) + .setTitle(C.cGreenB + "Archer's Bane") + .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 1) + .build(), 400) + .addEffects( + new MobaSpeedEffect(0.04) + ), +// new MobaItem(new ItemBuilder(Material.IRON_BOOTS) +// .setTitle(C.cYellowB + "Superior Archer's Bane") +// .addEnchantment(Enchantment.PROTECTION_PROJECTILE, 2) +// .build(), 750) +// .addEffects( +// new MobaSpeedEffect(0.06) +// ), + new MobaItem(new ItemBuilder(Material.IRON_BOOTS) + .setTitle(C.cGreenB + "Brawler's Plate") + .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build(), 400) + .addEffects( + new MobaSpeedEffect(0.04) + ), +// new MobaItem(new ItemBuilder(Material.IRON_BOOTS) +// .setTitle(C.cYellowB + "Superior Brawler's Plate") +// .addEnchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) +// .build(), 750) +// .addEffects( +// new MobaSpeedEffect(0.06) +// ), + new MobaItem(new ItemBuilder(Material.DIAMOND_BOOTS) + .setTitle(C.cDRedB + "Prince's Plate") + .build(), 2000) + .addEffects( + new MobaSpeedEffect(0.1) + ) + ), new ItemStack(Material.IRON_BOOTS)); + + public MobaWarriorShop(Moba host, MobaShop shop) + { + super(host, shop, MobaRole.WARRIOR); + + addCategory(SWORD); + addCategory(HELMET); + addCategory(CHESTPLATE); + addCategory(LEGGINGS); + addCategory(BOOTS); + addConsumables(); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePoint.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePoint.java new file mode 100644 index 000000000..11ab9881d --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePoint.java @@ -0,0 +1,301 @@ +package nautilus.game.arcade.game.games.moba.structure.point; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilFirework; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Effect; +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.Player; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +public class CapturePoint +{ + + private static final int MAX_RADIUS = 5; + private static final int MAX_PROGRESS = 5; + private static final int MAX_PROGRESS_NETURAL = 10; + private static final int MIN_INFORM_TIME = (int) TimeUnit.SECONDS.toMillis(30); + + private final Moba _host; + + private final String _name; + private final ChatColor _colour; + + private final Location _center; + private final List _wool; + private final List _changed; + + private final double _captureDist; + + private GameTeam _owner; + private GameTeam _side; + private int _progress; + private long _lastInform; + + public CapturePoint(Moba host, String name, ChatColor colour, Location center) + { + _host = host; + _name = name; + _colour = colour; + _center = center; + _wool = new ArrayList<>(36); + _changed = new ArrayList<>(_wool.size()); + + double highestDist = 0; + + for (Entry entry : UtilBlock.getInRadius(center, MAX_RADIUS).entrySet()) + { + Block block = entry.getKey(); + double offset = entry.getValue(); + + if (block.getType() != Material.WOOL) + { + continue; + } + + if (offset > highestDist) + { + highestDist = offset; + } + + _wool.add(block); + } + Collections.shuffle(_wool); + + _captureDist = highestDist * (double) MAX_RADIUS; + } + + public void update() + { + // Store the number of players in a team in this map + Map playersOnPoint = new HashMap<>(); + + for (GameTeam team : _host.GetTeamList()) + { + // Populate + playersOnPoint.put(team, 0); + int players = 0; + + for (Player player : team.GetPlayers(true)) + { + // Ignore for spectators + // If they are not in the range + if (UtilPlayer.isSpectator(player) || UtilMath.offset(player.getLocation(), _center) > _captureDist) + { + continue; + } + + // Increment + players++; + } + + // Put in map + playersOnPoint.put(team, players); + } + + // For each team get the team with the non-zero players + GameTeam highest = null; + for (Entry entry : playersOnPoint.entrySet()) + { + GameTeam team = entry.getKey(); + int players = entry.getValue(); + + // Only care if people are on it + if (players > 0) + { + // If this is the first team on the point + if (highest == null) + { + highest = team; + } + // This means there are 2 teams on the point + else + { + return; + } + } + } + + // No one at all is on the point + if (highest == null) + { + return; + } + // Players on the point + // Only inform if it has been a while + else if ((_owner == null || !_owner.equals(highest)) && UtilTime.elapsed(_lastInform, MIN_INFORM_TIME)) + { + _lastInform = System.currentTimeMillis(); + + for (Player player : Bukkit.getOnlinePlayers()) + { + player.playSound(player.getLocation(), Sound.GHAST_SCREAM2, 1, 1.0F); + } + + _host.Announce(F.main("Game", "Team " + highest.GetFormattedName() + C.mBody + " is capturing the " + _colour + _name + C.mBody + " Beacon!"), false); + //UtilTextMiddle.display("", "Team " + highest.GetFormattedName() + C.cWhite + " is capturing beacon " + _colour + _name, 0, 30, 10); + } + + // If it has just reached the maximum progress, set the owner. + if (_owner != null && _owner.equals(highest) && _progress >= (_owner == null ? MAX_PROGRESS_NETURAL : MAX_PROGRESS)) + { + return; + } + + capture(highest); + } + + private void capture(GameTeam team) + { + // No player has ever stood on the point + if (_side == null) + { + _side = team; + } + + // If it is the same team + if (_side.equals(team)) + { + // Increase progress + _progress++; + display(team, true); + + // Captured + if (_progress >= (_owner == null ? MAX_PROGRESS_NETURAL : MAX_PROGRESS)) + { + setOwner(team); + } + } + // Other team + else + { + // Point back to a neutral state + if (_progress == 0) + { + setBeaconColour(null); + _side = team; + // Recursively call this method now that the first (same team) condition will be true + capture(team); + return; + } + + _progress--; + display(team, false); + } + } + + private void setOwner(GameTeam team) + { + setBeaconColour(team); + + if (_owner != null) + { + // Same team no need to inform + if (_owner.equals(team)) + { + return; + } + } + else + { + // As the point is easier to capture after the initial capture + // We need to adjust the current progress, otherwise it has to go + // from 10 to 0 then to 5 which is unintended + _progress = MAX_PROGRESS; + } + + _owner = team; + + _host.Announce(F.main("Game", "Team " + team.GetFormattedName() + C.mBody + " captured the " + _colour + _name + C.mBody + " Beacon!")); + //UtilTextMiddle.display("", "Team " + team.GetFormattedName() + C.cWhite + " captured beacon " + _colour + _name, 0, 30, 10); + + UtilFirework.playFirework(_center, Type.BURST, team.GetColorBase(), false, false); + UtilServer.CallEvent(new CapturePointCaptureEvent(this)); + } + + private void display(GameTeam team, boolean forward) + { + double toChange = Math.ceil(_wool.size() / (_owner == null ? MAX_PROGRESS_NETURAL : MAX_PROGRESS)) + 1; + int changed = 0; + for (Block block : _wool) + { + if (changed >= toChange) + { + return; + } + + Block glass = block.getRelative(BlockFace.UP); + + if (forward) + { + if (_changed.contains(block)) + { + continue; + } + + block.setData(team.GetColorData()); + glass.setData(team.GetColorData()); + changed++; + _changed.add(block); + } + else + { + if (!_changed.contains(block)) + { + continue; + } + + block.setData((byte) 0); + glass.setData((byte) 0); + changed++; + _changed.remove(block); + } + + glass.getWorld().playEffect(glass.getLocation().add(0.5, 0.5, 0.5), Effect.STEP_SOUND, block.getType(), team.GetColorData()); + } + } + + private void setBeaconColour(GameTeam team) + { + byte colour = team == null ? 0 : team.GetColorData(); + + _center.getBlock().getRelative(BlockFace.DOWN).setData(colour); + } + + public String getName() + { + return _name; + } + + public ChatColor getColour() + { + return _colour; + } + + public GameTeam getOwner() + { + return _owner; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointCaptureEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointCaptureEvent.java new file mode 100644 index 000000000..c7443a151 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointCaptureEvent.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.structure.point; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class CapturePointCaptureEvent extends Event +{ + + private static final HandlerList _handlers = new HandlerList(); + + private CapturePoint _point; + + public CapturePointCaptureEvent(CapturePoint point) + { + _point = point; + } + + public CapturePoint getPoint() + { + return _point; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointManager.java new file mode 100644 index 000000000..51b6d7944 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/point/CapturePointManager.java @@ -0,0 +1,119 @@ +package nautilus.game.arcade.game.games.moba.structure.point; + +import mineplex.core.common.util.C; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.games.moba.Moba; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +public class CapturePointManager implements Listener +{ + + private final Moba _host; + + private final List _capturePoints; + + public CapturePointManager(Moba host) + { + _host = host; + + _capturePoints = new ArrayList<>(3); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (Entry entry : _host.getLocationStartsWith("POINT").entrySet()) + { + String[] split = entry.getKey().split(" "); + + if (split.length < 3) + { + continue; + } + + String name = split[1]; + ChatColor colour; + + try + { + colour = ChatColor.valueOf(split[2]); + } + catch (IllegalArgumentException e) + { + continue; + } + + _capturePoints.add(new CapturePoint(_host, name, colour, entry.getValue())); + } + } + + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC || !_host.IsLive()) + { + return; + } + + for (CapturePoint point : _capturePoints) + { + point.update(); + } + } + + public String getDisplayString() + { + StringBuilder out = new StringBuilder(); + + for (CapturePoint point : _capturePoints) + { + out.append(point.getOwner() == null ? C.cWhite : point.getOwner().GetColor()).append(point.getName()).append(" "); + } + + return out.toString().trim(); + } + +// public String getDisplayString(GameTeam team) +// { +// StringBuilder out = new StringBuilder(); +// int owned = 0; +// +// for (CapturePoint point : _capturePoints) +// { +// if (point.getOwner() == null || !point.getOwner().equals(team)) +// { +// continue; +// } +// +// out.append(point.getColour()).append("⚑ "); +// owned++; +// } +// +// while (owned++ < 3) +// { +// out.append(C.cGray).append("⚑ "); +// } +// +// return out.toString().trim(); +// } + + public List getCapturePoints() + { + return _capturePoints; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/Tower.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/Tower.java new file mode 100644 index 000000000..efb13fcb6 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/Tower.java @@ -0,0 +1,276 @@ +package nautilus.game.arcade.game.games.moba.structure.tower; + +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +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.UtilTime; +import mineplex.core.disguise.disguises.DisguiseGuardian; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Bukkit; +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.ArmorStand; +import org.bukkit.entity.EnderCrystal; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import java.util.concurrent.TimeUnit; + +public class Tower +{ + + private static final int DAMAGE = 3; + private static final int TARGET_RANGE = 10; + public static final int TARGET_RANGE_SQUARED = TARGET_RANGE * TARGET_RANGE; + private static final int MIN_INFORM_TIME = (int) TimeUnit.SECONDS.toMillis(30); + + private final Moba _host; + + private final Location _location; + private final GameTeam _team; + private float _fallbackYaw; + + private double _health; + private int _maxHealth; + private boolean _firstTower; + private boolean _dead; + private long _lastInform; + private double _damage; + + private ArmorStand _stand; + private DisguiseGuardian _guardian; + private EnderCrystal _crystal; + private LivingEntity _target; + + public Tower(Moba host, Location location, GameTeam team, int health, boolean firstTower) + { + _host = host; + _location = location; + _team = team; + _health = health; + _maxHealth = health; + _firstTower = firstTower; + _lastInform = System.currentTimeMillis(); + _damage = DAMAGE; + } + + public void setup() + { + _fallbackYaw = UtilAlg.GetYaw(UtilAlg.getTrajectory(_location, _host.GetSpectatorLocation())); + _location.setYaw(_fallbackYaw); + _stand = _location.getWorld().spawn(_location, ArmorStand.class); + _stand.setGravity(false); + _stand.setMaxHealth(_maxHealth); + _stand.setHealth(_health); + + _guardian = new DisguiseGuardian(_stand); + _host.getArcadeManager().GetDisguise().disguise(_guardian); + + if (!_firstTower) + { + _guardian.setElder(true); + } + + _guardian.setCustomNameVisible(true); + + _crystal = _location.getWorld().spawn(getTowerBase(), EnderCrystal.class); + _crystal.setCustomNameVisible(true); + + updateDisplay(); + } + + public void updateTarget() + { + if (_target == null) + { + // Reset damage + _damage = DAMAGE; + + // Target just entities + LivingEntity target = MobaUtil.getBestEntityTarget(_host, _team, _stand, _crystal.getLocation(), TARGET_RANGE, false); + + if (target == null) + { + // Try targeting players + target = MobaUtil.getBestEntityTarget(_host, _team, _stand, _crystal.getLocation(), TARGET_RANGE, true); + } + + _target = target; + setLaserTarget(target); + } + else + { + double dist = UtilMath.offsetSquared(_crystal.getLocation(), _target.getEyeLocation()); + + if (dist > TARGET_RANGE_SQUARED || UtilPlayer.isSpectator(_target) || _target.isDead() || !_target.isValid()) + { + _target = null; + setLaserTarget(null); + } + } + } + + public void updateDamage() + { + if (_target == null || _dead) + { + return; + } + + _target.getWorld().playSound(_target.getLocation(), Sound.EXPLODE, 1, 0.2F); + UtilParticle.PlayParticleToAll(ParticleType.LARGE_EXPLODE, _target.getLocation().add(0, 1.5, 0), 0, 0, 0, 0.2F, 1, ViewDist.LONG); + _host.getArcadeManager().GetDamage().NewDamageEvent(_target, null, null, DamageCause.CUSTOM, _damage++, false, true, false, "Tower", "Tower"); + } + + private void setLaserTarget(LivingEntity target) + { + if (target == null) + { + _guardian.setTarget(0); + + Location standLocation = _stand.getLocation(); + _guardian.getEntity().setLocation(standLocation.getX(), standLocation.getY(), standLocation.getZ(), _fallbackYaw, 0); + } + else + { + _guardian.setTarget(target.getEntityId()); + } + + _host.getArcadeManager().GetDisguise().updateDisguise(_guardian); + } + + public void damage(double damage) + { + _health -= damage; + + if (_health <= 0) + { + UtilServer.CallEvent(new TowerDestroyEvent(this)); + + // Boom! + explode(); + + for (Player player : Bukkit.getOnlinePlayers()) + { + player.playSound(player.getLocation(), Sound.BLAZE_BREATH, 1, 0.4F); + } + + _host.Announce(F.main("Game", _team.GetFormattedName() + C.mBody + " has lost a tower!"), false); + + // Nullify everything and remove all entities + _target = null; + setLaserTarget(null); + _dead = true; + _stand.remove(); + _crystal.remove(); + } + else + { + _stand.setHealth(_health); + updateDisplay(); + } + } + + private void updateDisplay() + { + String out = MobaUtil.getHealthBar(_stand, 40); + + _guardian.setName(out); + _crystal.setCustomName(out); + + if (UtilTime.elapsed(_lastInform, MIN_INFORM_TIME)) + { + _lastInform = System.currentTimeMillis(); + + for (Player player : _team.GetPlayers(true)) + { + player.playSound(player.getLocation(), Sound.ANVIL_LAND, 1, 0.5F); + player.sendMessage(F.main("Game", "Your Tower is under attack!")); + //UtilTextMiddle.display("", _team.GetColor() + "Your Tower is under attack!", 0, 30, 10, player); + } + } + } + + private void explode() + { + _host.getArcadeManager().GetExplosion().BlockExplosion(UtilBlock.getBlocksInRadius(_crystal.getLocation().add(0, 4, 0), 4), _location, false); + _location.getWorld().playSound(_location, Sound.EXPLODE, 2, 0.6F); + UtilParticle.PlayParticleToAll(ParticleType.HUGE_EXPLOSION, _location, 0, 0, 0, 0.1F, 1, ViewDist.LONG); + } + + private Location getTowerBase() + { + Block last = _location.getBlock(); + boolean firstAir = false; + + while (true) + { + last = last.getRelative(BlockFace.DOWN); + + if (!firstAir && last.getType() == Material.AIR) + { + firstAir = true; + } + else if (firstAir && last.getType() != Material.AIR) + { + break; + } + } + + return last.getLocation().add(0.5, 0.5, 0.5); + } + + public Location getLocation() + { + return _location; + } + + public GameTeam getOwner() + { + return _team; + } + + public ArmorStand getStand() + { + return _stand; + } + + public EnderCrystal getCrystal() + { + return _crystal; + } + + public boolean isFirstTower() + { + return _firstTower; + } + + public boolean isDead() + { + return _dead; + } + + public double getHealth() + { + return _health; + } + + public double getMaxHealth() + { + return _maxHealth; + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerDestroyEvent.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerDestroyEvent.java new file mode 100644 index 000000000..a7107a423 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerDestroyEvent.java @@ -0,0 +1,34 @@ +package nautilus.game.arcade.game.games.moba.structure.tower; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class TowerDestroyEvent extends Event +{ + + private static final HandlerList _handlers = new HandlerList(); + + private Tower _tower; + + public TowerDestroyEvent(Tower tower) + { + _tower = tower; + } + + public Tower getTower() + { + return _tower; + } + + public static HandlerList getHandlerList() + { + return _handlers; + } + + @Override + public HandlerList getHandlers() + { + return getHandlerList(); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerManager.java new file mode 100644 index 000000000..a7c9d4d54 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/structure/tower/TowerManager.java @@ -0,0 +1,378 @@ +package nautilus.game.arcade.game.games.moba.structure.tower; + +import mineplex.core.common.Pair; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.recharge.Recharge; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.util.MobaUtil; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.EnderCrystal; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.projectiles.ProjectileSource; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class TowerManager implements Listener +{ + + private static final int FIRST_TOWER_HEALTH = 500; + private static final int SECOND_TOWER_HEALTH = 1000; + private static final int PROJECTILE_RANGE_SQUARED = 4; + + private final Moba _host; + + private final List _towers; + private final Map> _projectilesToCheck; + + public TowerManager(Moba host) + { + _host = host; + + _towers = new ArrayList<>(12); + _projectilesToCheck = new HashMap<>(); + } + + @EventHandler + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + Map towers = _host.getLocationStartsWith("TOWER"); + + for (Entry entry : towers.entrySet()) + { + String key = entry.getKey(); + Location location = entry.getValue(); + String[] components = key.split(" "); + + if (components.length < 3) + { + continue; + } + + String team = components[1]; + + boolean firstTower; + + try + { + firstTower = components[2].equalsIgnoreCase("1"); + } + catch (NumberFormatException e) + { + continue; + } + + int health = firstTower ? FIRST_TOWER_HEALTH : SECOND_TOWER_HEALTH; + GameTeam gameTeam = _host.getTeam(team); + + if (gameTeam == null) + { + continue; + } + + _towers.add(new Tower(_host, location, gameTeam, health, firstTower)); + } + + _towers.sort((o1, o2) -> + { + if (o1.isFirstTower()) + { + return Integer.MIN_VALUE; + } + + if (!o2.isFirstTower()) + { + return Integer.MAX_VALUE; + } + + return 0; + }); + + _host.CreatureAllowOverride = true; + for (Tower tower : _towers) + { + tower.setup(); + } + _host.CreatureAllowOverride = false; + } + + @EventHandler + public void updateTower(UpdateEvent event) + { + if (!_host.IsLive()) + { + return; + } + + if (event.getType() == UpdateType.FASTEST) + { + for (Tower tower : _towers) + { + tower.updateTarget(); + } + } + else if (event.getType() == UpdateType.SEC) + { + for (Tower tower : _towers) + { + tower.updateDamage(); + } + } + } + + @EventHandler + public void guardianDamage(CustomDamageEvent event) + { + for (Tower tower : _towers) + { + if (tower.getStand().equals(event.GetDamageeEntity())) + { + tower.getStand().setFireTicks(0); + event.SetCancelled("Tower Guardian"); + } + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void crystalDamage(EntityDamageEvent event) + { + if (event.getEntity() instanceof EnderCrystal) + { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void crystalDamage(EntityDamageByEntityEvent event) + { + if (!(event.getEntity() instanceof EnderCrystal) || !_host.IsLive()) + { + return; + } + + Entity damager = event.getDamager(); + Player player = null; + Tower tower = null; + + for (Tower other : _towers) + { + if (other.getCrystal().equals(event.getEntity())) + { + tower = other; + break; + } + } + + if (tower == null) + { + return; + } + + if (damager instanceof Player) + { + player = (Player) damager; + } + else if (damager instanceof Projectile) + { + Projectile projectile = (Projectile) damager; + ProjectileSource source = projectile.getShooter(); + + if (source instanceof Player) + { + player = (Player) source; + } + } + + if (player == null) + { + return; + } + + GameTeam team = _host.GetTeam(player); + + if (UtilPlayer.isSpectator(player) || team == null || !canDamage(tower, team) || shouldCancelDamage(tower, player) || !Recharge.Instance.use(player, "Damage Tower", 200, false, false)) + { + return; + } + + tower.damage(event.getDamage()); + + if (Recharge.Instance.use(player, "Tower Sound", 500, false, false)) + { + playSound(player, tower); + } + } + + public void addProjectile(Player shooter, Entity entity, double damage) + { + _projectilesToCheck.put(entity, Pair.create(shooter, damage)); + } + + @EventHandler + public void updateProjectiles(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + return; + } + + Iterator iterator = _projectilesToCheck.keySet().iterator(); + + while (iterator.hasNext()) + { + Entity entity = iterator.next(); + Pair pair = _projectilesToCheck.get(entity); + Player player = pair.getLeft(); + GameTeam team = _host.GetTeam(player); + + for (Tower tower : _towers) + { + if (tower.isDead() || tower.getOwner().equals(team) || UtilMath.offsetSquared(tower.getCrystal(), entity) > PROJECTILE_RANGE_SQUARED) + { + continue; + } + + if (!shouldCancelDamage(tower, player)) + { + playSound(player, tower); + tower.damage(pair.getRight()); + } + + entity.remove(); + iterator.remove(); + } + } + } + + public Tower damageTowerAt(Location location, Player shooter, double damage) + { + GameTeam team = _host.GetTeam(shooter); + + if (team == null) + { + return null; + } + + for (Tower tower : _towers) + { + if (tower.isDead() || tower.getOwner().equals(team) || UtilMath.offsetSquared(tower.getCrystal().getLocation(), location) > PROJECTILE_RANGE_SQUARED) + { + continue; + } + + playSound(shooter, tower); + tower.damage(damage); + return tower; + } + + return null; + } + + private boolean shouldCancelDamage(Tower tower, Player shooter) + { + Location entityLocation = tower.getCrystal().getLocation(); + Location playerLocation = shooter.getLocation(); + playerLocation.setY(entityLocation.getY()); + + if (UtilMath.offsetSquared(playerLocation, entityLocation) > Tower.TARGET_RANGE_SQUARED) + { + shooter.playSound(shooter.getLocation(), Sound.NOTE_PLING, 1, 0.9F); + if (Recharge.Instance.use(shooter, "Tower Cancel Inform", 2000, false, false)) + { + shooter.sendMessage(F.main("Game", "You cannot damage the enemy tower while outside of the circle! Step inside the circle to deal damage to it.")); + } + + return true; + } + + return false; + } + + private void playSound(Player player, Tower tower) + { + player.playSound(tower.getCrystal().getLocation(), Sound.BLAZE_HIT, 1, 0.8F); + } + + public boolean canDamage(Tower tower, GameTeam team) + { + // Dead tower, nothing + // Same team + if (tower.isDead() || team.equals(tower.getOwner())) + { + return false; + } + + // First tower, all it + if (tower.isFirstTower()) + { + return true; + } + + // Second tower + // Need to check if previous was destroyed + for (Tower other : _towers) + { + // Is other team + // Is first tower + // Is same lane + // Is dead + if (!team.equals(other.getOwner()) && other.isFirstTower() && other.isDead()) + { + return true; + } + } + + return false; + } + + public String getDisplayString(GameTeam team) + { + StringBuilder out = new StringBuilder(); + + for (Tower tower : _towers) + { + if (!tower.getOwner().equals(team)) + { + continue; + } + + double health = tower.getHealth() / tower.getMaxHealth(); + String colour = tower.isDead() ? C.cGray : MobaUtil.getColour(health); + + out.append(colour).append("♛ "); + } + + return out.toString(); + } + + public List getTowers() + { + return _towers; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaConstants.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaConstants.java new file mode 100644 index 000000000..3dab8cbf2 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaConstants.java @@ -0,0 +1,17 @@ +package nautilus.game.arcade.game.games.moba.util; + +public class MobaConstants +{ + + // String constants + public static final String BASIC_ATTACK = "Basic Attack"; + public static final String AMMO = "Ammo"; + public static final String TEAM_METADATA = "team"; + + // Location Constants + public static final String MINION_PATH_START = "WHITE"; + public static final String MINION_PATH = "BROWN"; + public static final String SHOP = "SILVER"; + + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaParticles.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaParticles.java new file mode 100644 index 000000000..0964306f4 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaParticles.java @@ -0,0 +1,16 @@ +package nautilus.game.arcade.game.games.moba.util; + +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import org.bukkit.entity.LivingEntity; + +public class MobaParticles +{ + + public static void healing(LivingEntity entity, int amount) + { + UtilParticle.PlayParticleToAll(ParticleType.HEART, entity.getLocation().add(0, 1.3, 0), 0.5F, 0.5F, 0.5F, 0.1F, amount, ViewDist.LONG); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaUtil.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaUtil.java new file mode 100644 index 000000000..ac09e9aac --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/moba/util/MobaUtil.java @@ -0,0 +1,232 @@ +package nautilus.game.arcade.game.games.moba.util; + +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.UtilServer; +import nautilus.game.arcade.game.GameTeam; +import nautilus.game.arcade.game.games.moba.Moba; +import nautilus.game.arcade.game.games.moba.kit.hp.MobaHPRegenEvent; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +public class MobaUtil +{ + + public static LivingEntity getBestEntityTarget(Moba host, GameTeam owner, LivingEntity source, Location location, int targetRange, boolean targetPlayers) + { + LivingEntity highest = null; + double bestDist = 0; + + for (Entry entry : UtilEnt.getInRadius(location, targetRange).entrySet()) + { + LivingEntity entity = entry.getKey(); + double dist = entry.getValue(); + + if (source.equals(entity)) + { + continue; + } + + // Check for team entities + if (entity.hasMetadata(MobaConstants.TEAM_METADATA) && entity.getMetadata(MobaConstants.TEAM_METADATA).get(0).asString().equals(owner.GetName())) + { + continue; + } + + // Ignore players on the same team + if (entity instanceof Player) + { + if (!targetPlayers || owner.equals(host.GetTeam((Player) entity))) + { + continue; + } + } + + if (bestDist < dist) + { + highest = entity; + bestDist = dist; + } + } + + return highest; + } + + public static boolean isInBoundary(GameTeam owner, LivingEntity source, Location center, List boundaries, LivingEntity target) + { + return getEntitiesInBoundary(owner, source, center, boundaries).contains(target); + } + + public static LivingEntity getBestEntityTarget(GameTeam owner, LivingEntity source, Location center, List boundaries) + { + LivingEntity best = null; + double bestDist = Double.MAX_VALUE; + + for (LivingEntity entity : getEntitiesInBoundary(owner, source, center, boundaries)) + { + double dist = UtilMath.offsetSquared(entity.getLocation(), center); + + if (dist < bestDist) + { + best = entity; + bestDist = dist; + } + } + + return best; + } + + public static Set getEntitiesInBoundary(GameTeam owner, LivingEntity source, Location center, List boundaries) + { + Set entities = new HashSet<>(); + List ignored = new ArrayList<>(); + + if (owner != null) + { + // Add teammates to ignored players + ignored.addAll(owner.GetPlayers(true)); + } + + // For each boundary + for (Location boundary : boundaries) + { + Location checking = center.clone(); + // Get direction from center to boundary + Vector direction = UtilAlg.getTrajectory(center, boundary); + // Store the checked distance + double checkedDist = 0; + // Get the distance squared from the center to the boundary + double maxDist = UtilMath.offsetSquared(center, boundary); + + // Keep advancing the distance until it hits the boundary + while (checkedDist * checkedDist < maxDist) + { + // Advance the location + checking.add(direction); + + // Check for nearby entities + for (LivingEntity entity : UtilEnt.getInRadius(checking, 3).keySet()) + { + if (source.equals(entity) || ignored.contains(entity)) + { + continue; + } + + // Check for team entities + if (owner != null && isTeamEntity(entity, owner)) + { + continue; + } + + entities.add(entity); + } + + checkedDist++; + } + } + + return entities; + } + + public static String getHealthBar(LivingEntity entity, int bars) + { + return getHealthBar(entity, entity.getHealth(), bars); + } + + public static String getHealthBar(LivingEntity entity, double newHealth, int bars) + { + StringBuilder out = new StringBuilder(); + double health = newHealth / entity.getMaxHealth(); + String colour = getColour(health); + + for (int i = 0; i < bars; i++) + { + double cur = i * (1D / (double) bars); + + if (cur < health) + { + out.append(colour).append("|"); + } + else + { + out.append(C.cGrayB).append("|"); + } + } + + return out.toString(); + } + + public static String getColour(double percentage) + { + if (percentage < 0.25) + { + return C.cRedB; + } + else if (percentage < 0.5) + { + return C.cGoldB; + } + else if (percentage < 0.75) + { + return C.cYellowB; + } + + return C.cGreenB; + } + + public static void setTeamEntity(LivingEntity entity, GameTeam team) + { + entity.setMetadata(MobaConstants.TEAM_METADATA, new FixedMetadataValue(UtilServer.getPlugin(), team.GetName())); + } + + public static boolean isTeamEntity(LivingEntity entity, GameTeam team) + { + return entity.hasMetadata(MobaConstants.TEAM_METADATA) && entity.getMetadata(MobaConstants.TEAM_METADATA).get(0).asString().equals(team.GetName()); + } + + public static void heal(LivingEntity entity, Player source, double health) + { + if (entity instanceof Player) + { + MobaHPRegenEvent regenEvent = new MobaHPRegenEvent((Player) entity, source, health, false); + UtilServer.CallEvent(regenEvent); + + if (regenEvent.isCancelled()) + { + return; + } + + health = regenEvent.getHealth(); + } + + entity.setHealth(Math.min(entity.getHealth() + health, entity.getMaxHealth())); + } + + public static double scaleDamageWithBow(ItemStack itemStack, double initialDamage) + { + // Set a base damage + initialDamage += 5; + + // Scale damage with the damage on the player's bow + if (itemStack != null && itemStack.getType() == Material.BOW) + { + initialDamage += initialDamage * itemStack.getEnchantmentLevel(Enchantment.ARROW_DAMAGE) * 0.25; + } + + return initialDamage; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/Skyfall.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/Skyfall.java index 7fb612534..b5ca174a0 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/Skyfall.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/Skyfall.java @@ -75,6 +75,7 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent; import nautilus.game.arcade.ArcadeManager; import nautilus.game.arcade.GameType; +import nautilus.game.arcade.events.ChestRefillEvent; import nautilus.game.arcade.events.GameStateChangeEvent; import nautilus.game.arcade.game.Game; import nautilus.game.arcade.game.games.skyfall.kits.KitAeronaught; @@ -83,6 +84,7 @@ import nautilus.game.arcade.game.games.skyfall.kits.KitDeadeye; import nautilus.game.arcade.game.games.skyfall.kits.KitJouster; import nautilus.game.arcade.game.games.skyfall.kits.KitSpeeder; import nautilus.game.arcade.game.games.skyfall.kits.KitStunner; +import nautilus.game.arcade.game.games.skyfall.quests.RingQuestTracker; import nautilus.game.arcade.game.games.skyfall.stats.AeronaughtStatTracker; import nautilus.game.arcade.game.games.skyfall.stats.RingStatTracker; import nautilus.game.arcade.game.games.survivalgames.SupplyChestOpenEvent; @@ -193,6 +195,8 @@ public abstract class Skyfall extends Game new RingStatTracker(this), new AeronaughtStatTracker(this)); + registerQuestTrackers(new RingQuestTracker(this)); + registerChatStats( Kills, Assists, @@ -328,8 +332,12 @@ public abstract class Skyfall extends Game _chestsRefilled = System.currentTimeMillis(); _refillAnnounced = false; - _lowerIsland.refillChests(); + ChestRefillEvent refillEvent = UtilServer.CallEvent(new ChestRefillEvent(_lowerIsland.getChests())); + if (refillEvent.isCancelled()) + return; + _lowerIsland.refillChests(); + Announce(ChatColor.AQUA + "" + ChatColor.BOLD + "Chests on the lower middle Island have been refilled!", true); } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/quests/RingQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/quests/RingQuestTracker.java new file mode 100644 index 000000000..4a8c0445f --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/skyfall/quests/RingQuestTracker.java @@ -0,0 +1,37 @@ +package nautilus.game.arcade.game.games.skyfall.quests; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.games.skyfall.PlayerBoostRingEvent; +import nautilus.game.arcade.game.games.skyfall.Skyfall; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * BoosterRingQuestTracker + * + * @author xXVevzZXx + */ +public class RingQuestTracker extends QuestTracker +{ + + public RingQuestTracker(Skyfall game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler(priority=EventPriority.MONITOR) + public void boosterRing(PlayerBoostRingEvent event) + { + if (event.isCancelled()) + return; + + if (!getGame().IsAlive(event.getPlayer())) + return; + + incrementQuests(event.getPlayer(), 1, "Booster Rings", getGame().GetKit(event.getPlayer()).GetName() + "Kit"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/SpeedBuilders.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/SpeedBuilders.java index 3a04f2237..186b91746 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/SpeedBuilders.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/SpeedBuilders.java @@ -32,12 +32,14 @@ import nautilus.game.arcade.events.GameStateChangeEvent; import nautilus.game.arcade.game.GameTeam; import nautilus.game.arcade.game.GameTeam.PlayerState; import nautilus.game.arcade.game.SoloGame; +import nautilus.game.arcade.game.games.skyfall.quests.RingQuestTracker; import nautilus.game.arcade.game.games.speedbuilders.data.BuildData; import nautilus.game.arcade.game.games.speedbuilders.data.DemolitionData; import nautilus.game.arcade.game.games.speedbuilders.data.MobData; import nautilus.game.arcade.game.games.speedbuilders.data.RecreationData; import nautilus.game.arcade.game.games.speedbuilders.events.PerfectBuildEvent; import nautilus.game.arcade.game.games.speedbuilders.kits.DefaultKit; +import nautilus.game.arcade.game.games.speedbuilders.quests.PerfectBuildQuestTracker; import nautilus.game.arcade.game.games.speedbuilders.stattrackers.DependableTracker; import nautilus.game.arcade.game.games.speedbuilders.stattrackers.FirstBuildTracker; import nautilus.game.arcade.game.games.speedbuilders.stattrackers.PerfectionistTracker; @@ -190,6 +192,8 @@ public class SpeedBuilders extends SoloGame new SpeediestBuilderizerTracker(this), new BlockPlaceStatTracker(this, new Material[] {}) ); + + registerQuestTrackers(new PerfectBuildQuestTracker(this)); registerChatStats( new ChatStatData("BlocksPlaced", "Blocks Placed", true), diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/quests/PerfectBuildQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/quests/PerfectBuildQuestTracker.java new file mode 100644 index 000000000..b26e80bc0 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/speedbuilders/quests/PerfectBuildQuestTracker.java @@ -0,0 +1,29 @@ +package nautilus.game.arcade.game.games.speedbuilders.quests; + +import org.bukkit.event.EventHandler; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.games.speedbuilders.SpeedBuilders; +import nautilus.game.arcade.game.games.speedbuilders.events.PerfectBuildEvent; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * PerfectBuildQuestTracker + * + * @author xXVevzZXx + */ +public class PerfectBuildQuestTracker extends QuestTracker +{ + + public PerfectBuildQuestTracker(SpeedBuilders game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler + public void onPerfectBuild(PerfectBuildEvent event) + { + incrementQuests(event.getPlayer(), 1, "Perfect Build"); + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/survivalgames/SurvivalGames.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/survivalgames/SurvivalGames.java index 7596dc85c..d9477949f 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/survivalgames/SurvivalGames.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/survivalgames/SurvivalGames.java @@ -112,6 +112,7 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent; import nautilus.game.arcade.ArcadeManager; import nautilus.game.arcade.GameType; +import nautilus.game.arcade.events.ChestRefillEvent; import nautilus.game.arcade.events.GameStateChangeEvent; import nautilus.game.arcade.game.Game; import nautilus.game.arcade.game.GameTeam; @@ -1485,7 +1486,11 @@ public abstract class SurvivalGames extends Game public void refillChests() { ArrayList list = new ArrayList(_lootedBlocks); - + + ChestRefillEvent event = UtilServer.CallEvent(new ChestRefillEvent(list)); + if (event.isCancelled()) + return; + _lootedBlocks.clear(); WorldServer world = list.isEmpty() ? null : ((CraftWorld) list.get(0) diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java index ce027ddac..8a26603b4 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/UHC.java @@ -103,6 +103,7 @@ import nautilus.game.arcade.game.games.AbsorptionFix; import nautilus.game.arcade.game.games.uhc.components.UHCBorder; import nautilus.game.arcade.game.games.uhc.components.UHCFreezer; import nautilus.game.arcade.game.games.uhc.components.UHCSpeedMode; +import nautilus.game.arcade.game.games.uhc.quests.TameQuestTracker; import nautilus.game.arcade.game.games.uhc.stat.CollectFoodStat; import nautilus.game.arcade.game.games.uhc.stat.HalfHeartHealStat; import nautilus.game.arcade.game.games.uhc.stat.HoeCraftingStat; @@ -211,6 +212,8 @@ public abstract class UHC extends Game _state = UHCState.SAFE; + Prepare = false; + HideTeamSheep = true; StrictAntiHack = true; @@ -294,6 +297,8 @@ public abstract class UHC extends Game registerStatTrackers(new CollectFoodStat(this), new HoeCraftingStat(this), new LuckyMinerStat(this), new HalfHeartHealStat(this)); + registerQuestTrackers(new TameQuestTracker(this)); + registerDebugCommand(new DebugCommand("startpvp", Rank.ADMIN) { @Override diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/quests/TameQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/quests/TameQuestTracker.java new file mode 100644 index 000000000..e5a3df895 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/games/uhc/quests/TameQuestTracker.java @@ -0,0 +1,38 @@ +package nautilus.game.arcade.game.games.uhc.quests; + +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityTameEvent; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.games.uhc.UHC; +import nautilus.game.arcade.quest.QuestTracker; + +/** + * TameQuestTracker + * + * @author xXVevzZXx + */ +public class TameQuestTracker extends QuestTracker +{ + + public TameQuestTracker(UHC game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler + public void tameEvent(EntityTameEvent event) + { + if (!getGame().IsLive()) + return; + + if (event.getEntityType() != EntityType.HORSE) + return; + + incrementQuests((Player) event.getOwner(), 1, "Tamed Horse"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/modules/CustomScoreboardModule.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/modules/CustomScoreboardModule.java new file mode 100644 index 000000000..928a2e919 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/game/modules/CustomScoreboardModule.java @@ -0,0 +1,370 @@ +package nautilus.game.arcade.game.modules; + +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game.GameState; +import nautilus.game.arcade.scoreboard.GameScoreboard; +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.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +/** + * CustomScoreboardModule allows for the use of per-player scoreboards in an Arcade game. + * Including sidebars, tab-list prefixes, suffixes, undernames and scores.
+ * These scoreboard system is backed by {@link mineplex.core.scoreboard.ScoreboardManager} and is thus optimised + * extremely efficiently, so don't be afraid to call the set methods often as they will not be updated then and there.
+ * Scoreboards are refreshed for all players upon the prepare, live and end state changes. While sidebars are updated every 10 ticks/0.5 seconds.
+ * If you wish to update the scoreboard more frequently than these, the methods: + *

    + *
  • {@link #refresh()}
  • + *
  • {@link #refreshAsPerspective(Player)}
  • + * + *
+ * + * @see mineplex.core.scoreboard.MineplexScoreboard + * @see nautilus.game.arcade.game.games.moba.Moba + */ +public class CustomScoreboardModule extends Module +{ + + private final Map _scoreboard; + + private BiConsumer _scoreboardConsumer; + private BiFunction _prefixFunction; + private BiFunction _suffixFunction; + private BiFunction _tabListFunction; + private String _underNameObjective; + private BiFunction _underNameFunction; + + public CustomScoreboardModule() + { + _scoreboard = new HashMap<>(); + } + + /** + * The use of the boolean UseCustomScoreboard in {@link nautilus.game.arcade.game.Game} is required so the Arcade doesn't + * try and create the scoreboard itself or reference the standard {@link GameScoreboard}, which it does (a lot). + */ + @Override + protected void setup() + { + getGame().UseCustomScoreboard = true; + } + + /** + * Calls {@link #setupScoreboard(Player)} when the players joins, if the game is not in a Lobby state. + */ + @EventHandler + public void playerJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + GameState state = getGame().GetState(); + + if (state == GameState.Loading || state == GameState.Recruit) + { + return; + } + + setupScoreboard(player); + } + + /** + * Removes the player's scoreboard from the {@link #_scoreboard} map. + *
+ * Unregisters the quitting player's entries from all other scoreboards. + */ + @EventHandler + public void playerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + + _scoreboard.remove(player.getUniqueId()); + + for (CustomArcadeScoreboard scoreboard : _scoreboard.values()) + { + scoreboard.getHandle().getTeam(player.getName()).unregister(); + } + } + + /** + * Calls {@link #setupScoreboard(Player)} when the game switches to the prepare state. + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void prepare(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare) + { + return; + } + + for (Player player : Bukkit.getOnlinePlayers()) + { + setupScoreboard(player); + } + } + + /** + * Refreshes all player scoreboards upon an in progress state change. + */ + @EventHandler(priority = EventPriority.MONITOR) + public void live(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Prepare && event.GetState() != GameState.Live && event.GetState() != GameState.End) + { + return; + } + + refresh(); + } + + /** + * Calls the draw method every 10 ticks/0.5 seconds. + */ + @EventHandler + public void update(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + for (CustomArcadeScoreboard scoreboard : _scoreboard.values()) + { + scoreboard.draw(); + } + } + + private void setupScoreboard(Player player) + { + UUID key = player.getUniqueId(); + CustomArcadeScoreboard scoreboard = _scoreboard.get(key); + + if (scoreboard == null) + { + scoreboard = new CustomArcadeScoreboard(player); + _scoreboard.put(player.getUniqueId(), scoreboard); + } + + player.setScoreboard(scoreboard.getHandle()); + } + + public CustomScoreboardModule setSidebar(BiConsumer consumer) + { + _scoreboardConsumer = consumer; + return this; + } + + public CustomScoreboardModule setPrefix(BiFunction function) + { + _prefixFunction = function; + return this; + } + + public CustomScoreboardModule setSuffix(BiFunction function) + { + _suffixFunction = function; + return this; + } + + public CustomScoreboardModule setTabList(BiFunction function) + { + _tabListFunction = function; + return this; + } + + public CustomScoreboardModule setUnderNameObjective(String name) + { + _underNameObjective = name; + return this; + } + + public CustomScoreboardModule setUnderName(BiFunction function) + { + _underNameFunction = function; + return this; + } + + /** + * Refreshes all player's scoreboards. + */ + public void refresh() + { + for (CustomArcadeScoreboard scoreboard : _scoreboard.values()) + { + scoreboard.draw(false); + } + } + + /** + * Refreshes an individual player's scoreboard. + * + * @param perspective The player that has the perspective of the scoreboard to be refreshed. + */ + public void refreshAsPerspective(Player perspective) + { + CustomArcadeScoreboard scoreboard = _scoreboard.get(perspective.getUniqueId()); + + if (scoreboard == null) + { + return; + } + + scoreboard.draw(false); + } + + /** + * Refreshes all scoreboards but only where the subject of said scoreboard is the player passed in as the subject parameter. + */ + public void refreshAsSubject(Player subject) + { + for (CustomArcadeScoreboard scoreboard : _scoreboard.values()) + { + scoreboard.draw(subject); + } + } + + @Override + public void cleanup() + { + _scoreboard.clear(); + } + + /** + * An internal class that simply implements the actions set out by {@link CustomScoreboardModule}. + */ + class CustomArcadeScoreboard extends GameScoreboard + { + + CustomArcadeScoreboard(Player owner) + { + super(getGame(), owner); + } + + private void updateTag(Player subject) + { + Scoreboard handle = getHandle(); + String teamName = subject.getName(); + Team team = handle.getTeam(teamName); + + String prefix = _prefixFunction == null ? null : _prefixFunction.apply(getOwner(), subject); + String suffix = _suffixFunction == null ? null : _suffixFunction.apply(getOwner(), subject); + + if (team == null) + { + team = handle.registerNewTeam(teamName); + team.addEntry(subject.getName()); + } + + if (prefix != null) + { + if (team.getPrefix() == null || !team.getPrefix().equals(prefix)) + { + team.setPrefix(prefix); + } + } + if (suffix != null) + { + if (team.getSuffix() == null || !team.getSuffix().equals(suffix)) + { + team.setSuffix(suffix); + } + } + } + + private void updateTabList(Player subject) + { + if (_tabListFunction == null) + { + return; + } + + Scoreboard handle = getHandle(); + Objective objective = handle.getObjective(DisplaySlot.PLAYER_LIST); + int value = _tabListFunction.apply(getOwner(), subject); + + if (objective == null) + { + objective = handle.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 (_underNameFunction == null || _underNameObjective == null) + { + return; + } + + Scoreboard handle = getHandle(); + Objective objective = handle.getObjective(DisplaySlot.BELOW_NAME); + int value = _underNameFunction.apply(getOwner(), subject); + + if (objective == null) + { + objective = handle.registerNewObjective(_underNameObjective, "dummy"); + objective.setDisplaySlot(DisplaySlot.BELOW_NAME); + } + + Score score = objective.getScore(subject.getName()); + + if (score.getScore() != value) + { + score.setScore(value); + } + } + + @Override + public void draw() + { + draw(true); + } + + public void draw(boolean sidebarOnly) + { + if (_scoreboardConsumer != null) + { + _scoreboardConsumer.accept(getOwner(), this); + } + if (!sidebarOnly) + { + for (Player player : Bukkit.getOnlinePlayers()) + { + draw(player); + } + } + super.draw(); + } + + private void draw(Player player) + { + updateTag(player); + updateTabList(player); + updateUnderName(player); + } + } + + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/kit/Kit.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/kit/Kit.java index bc6d41347..dbfe01cf6 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/kit/Kit.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/kit/Kit.java @@ -6,6 +6,7 @@ import nautilus.game.arcade.ArcadeFormat; import nautilus.game.arcade.ArcadeManager; import nautilus.game.arcade.events.PlayerKitGiveEvent; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.*; diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java index 126bb399b..f046626b4 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameHostManager.java @@ -104,7 +104,7 @@ public class GameHostManager implements Listener ultraGames.add(GameType.MonsterMaze); ultraGames.add(GameType.Gladiators); - //Hero Games + //HeroKit Games heroGames.add(GameType.ChampionsDominate); heroGames.add(GameType.ChampionsTDM); heroGames.add(GameType.ChampionsCTF); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameManager.java index 6d3c8e18b..57a1eff12 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GameManager.java @@ -475,9 +475,12 @@ public class GameManager implements Listener return; Game game = Manager.GetGame(); - if (game == null) return; - - game.GetScoreboard().updateTitle(); + if (game == null) return; + + if (!game.UseCustomScoreboard) + { + game.GetScoreboard().updateTitle(); + } } public void TeamPreferenceJoin(Game game) @@ -636,7 +639,7 @@ public class GameManager implements Listener return; // Sir, I'll handle this. - if (game instanceof UHC) + if (!game.Prepare) return; final ArrayList players = game.GetPlayers(true); @@ -672,21 +675,24 @@ public class GameManager implements Listener } }, i * game.TickPerTeleport); } - - //Announce Game after every player is TP'd in - UtilServer.getServer().getScheduler().runTaskLater(Manager.getPlugin(), new Runnable() + + if (game.PrepareAutoAnnounce) { - public void run() + //Announce Game after every player is TP'd in + UtilServer.getServer().getScheduler().runTaskLater(Manager.getPlugin(), new Runnable() { - game.AnnounceGame(); - game.StartPrepareCountdown(); - - //Event - GamePrepareCountdownCommence event = new GamePrepareCountdownCommence(game); - UtilServer.getServer().getPluginManager().callEvent(event); - } - }, players.size() * game.TickPerTeleport); - + public void run() + { + game.AnnounceGame(); + game.StartPrepareCountdown(); + + //Event + GamePrepareCountdownCommence event = new GamePrepareCountdownCommence(game); + UtilServer.getServer().getPluginManager().callEvent(event); + } + }, players.size() * game.TickPerTeleport); + } + //Spectators Move for (Player player : UtilServer.getPlayers()) { diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GamePlayerManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GamePlayerManager.java index 00e52236a..98d0cfb35 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GamePlayerManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/GamePlayerManager.java @@ -2,6 +2,7 @@ package nautilus.game.arcade.managers; import java.util.ArrayList; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; @@ -83,14 +84,15 @@ public class GamePlayerManager implements Listener final Player player = event.getPlayer(); //Player List - UtilTabTitle.setHeaderAndFooter(player, - Manager.GetGame() != null ? C.cGold + C.Bold + Manager.GetGame().GetType().GetName() : " ", - "Visit " + C.cGreen + "www.mineplex.com" + ChatColor.RESET + " for News, Forums and Shop"); + UtilTabTitle.setHeaderAndFooter(player, + Manager.GetGame() != null ? C.cGold + C.Bold + Manager.GetGame().GetType().GetName() : " ", + "Visit " + C.cGreen + "www.mineplex.com" + ChatColor.RESET + " for News, Forums and Shop"); //Lobby Spawn if (Manager.GetGame() == null || !Manager.GetGame().InProgress()) { Manager.Clear(player); + Manager.getScoreboardManager().getScoreboards().entrySet().stream().filter(ent -> Bukkit.getPlayer(ent.getKey()) != null).forEach(ent -> Bukkit.getPlayer(ent.getKey()).setScoreboard(ent.getValue().getHandle())); player.teleport(Manager.GetLobby().getSpawn()); //Load default kit for this game if (Manager.GetGame() != null && Manager.GetGame().GetType().name().toLowerCase().contains("champions")) @@ -133,19 +135,24 @@ public class GamePlayerManager implements Listener if (loc != null && !loc.getWorld().getName().equalsIgnoreCase("world")) { player.teleport(loc); - } else + } + else { Manager.Clear(player); player.teleport(Manager.GetGame().GetTeam(player).GetSpawn()); } - } else + } + else { Manager.Clear(player); Manager.addSpectator(player, true); UtilPlayer.message(player, F.main("Game", Manager.GetGame().GetName() + " is in progress, please wait for next game!")); } - player.setScoreboard(Manager.GetGame().GetScoreboard().getScoreboard()); + if (!Manager.GetGame().UseCustomScoreboard) + { + player.setScoreboard(Manager.GetGame().GetScoreboard().getScoreboard()); + } } @EventHandler diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/LobbyManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/LobbyManager.java index 72f1dc35f..5f83fe93d 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/LobbyManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/LobbyManager.java @@ -53,6 +53,7 @@ import org.bukkit.event.player.PlayerVelocityEvent; import org.bukkit.event.weather.WeatherChangeEvent; import org.bukkit.scoreboard.Team; +import java.io.File; import java.util.Map; /** @@ -83,12 +84,13 @@ public abstract class LobbyManager implements Listener private Location _kitText; private Location _teamText; private Location _carl; + private Location _missions; private Location _spawn; private Location _ampStand; private boolean _colorTick = false; private boolean _generatePodiums = false; - public LobbyManager(ArcadeManager manager, Location carl, Location spawn, Location ampStand) + public LobbyManager(ArcadeManager manager, Location missions, Location carl, Location spawn, Location ampStand) { _manager = manager; @@ -116,7 +118,7 @@ public abstract class LobbyManager implements Listener _serverName = _serverName.substring(0, Math.min(16, _serverName.length())); _serverGroup = _manager.GetServerConfig().ServerGroup; - _generatePodiums = _serverGroup.equalsIgnoreCase("MiniGames") || manager.GetHost() != null; + _generatePodiums = new File("world/GENPODIUMS.dat").exists() || manager.GetHost() != null; if (_generatePodiums) { @@ -479,10 +481,14 @@ public abstract class LobbyManager implements Listener return; } - if (_manager.GetGame() != null && - (_manager.GetGame().GetState() != GameState.Loading && - _manager.GetGame().GetState() != GameState.Recruit)) + Game game = _manager.GetGame(); + if (game != null && game.GetState() != GameState.Loading && game.GetState() != GameState.Recruit) { + if (game.UseCustomScoreboard) + { + return; + } + for (Player player : UtilServer.getPlayers()) player.setScoreboard(_manager.GetGame().GetScoreboard().getScoreboard()); //XXX } @@ -892,4 +898,14 @@ public abstract class LobbyManager implements Listener { return _generatePodiums; } + + public Location getMissions() + { + return _missions; + } + + public void setMissions(Location loc) + { + _missions = loc; + } } diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/current/NewGameLobbyManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/current/NewGameLobbyManager.java index 11b970117..e813e21bd 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/current/NewGameLobbyManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/current/NewGameLobbyManager.java @@ -58,6 +58,7 @@ public class NewGameLobbyManager extends LobbyManager public enum DataLoc { CARL, + MISSIONS, AMP, SPAWN,; } @@ -70,7 +71,7 @@ public class NewGameLobbyManager extends LobbyManager public NewGameLobbyManager(ArcadeManager manager) { - super(manager, null, null, null); + super(manager, null, null, null, null); _run = CONFIG.exists(); if (_run) @@ -519,7 +520,7 @@ public class NewGameLobbyManager extends LobbyManager continue; } - if (!lastName.equalsIgnoreCase("SPAWN") || lastName.equalsIgnoreCase("CARL")) + if (!lastName.equalsIgnoreCase("SPAWN") || lastName.equalsIgnoreCase("CARL") || lastName.equalsIgnoreCase("MISSIONS")) { loc.subtract(0, 0.5, 0); } @@ -557,6 +558,16 @@ public class NewGameLobbyManager extends LobbyManager setCarl(carl); } + + Location missions = _singleLocs.get(DataLoc.MISSIONS.name()); + if (missions != null) + { + missions.add(0, 0.5, 0); + float yaw = UtilAlg.GetYaw(UtilAlg.getTrajectory2d(missions, getSpawn())); + missions.setYaw(yaw); + + setMissions(missions); + } Location amp = _singleLocs.get(DataLoc.AMP.name()); if (amp != null) diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/legacy/LegacyGameLobbyManager.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/legacy/LegacyGameLobbyManager.java index 2d988d0d5..9b275c0bd 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/legacy/LegacyGameLobbyManager.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/managers/lobby/legacy/LegacyGameLobbyManager.java @@ -39,7 +39,7 @@ public class LegacyGameLobbyManager extends LobbyManager public LegacyGameLobbyManager(ArcadeManager manager) { - super(manager, null, null, new Location(UtilWorld.getWorld("world"), 0, 102.5, -15)); + super(manager, null, null, null, new Location(UtilWorld.getWorld("world"), 0, 102.5, -15)); setSpawn(new Location(WORLD, 0, 104, 0, 0, 0)); diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ChestOpenQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ChestOpenQuestTracker.java new file mode 100644 index 000000000..30cbb77d2 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ChestOpenQuestTracker.java @@ -0,0 +1,57 @@ +package nautilus.game.arcade.quest; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.bukkit.Location; +import org.bukkit.Material; +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.player.PlayerInteractEvent; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.Game; + +/** + * ChestOpenQuestTracker + * + * @author xXVevzZXx + */ +public class ChestOpenQuestTracker extends QuestTracker +{ + private HashMap> _usedChests = new HashMap<>(); + + public ChestOpenQuestTracker(Game game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler(priority=EventPriority.HIGHEST) + public void chestRegister(PlayerInteractEvent event) + { + if (!getGame().IsLive()) + return; + + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) + return; + + if (event.getClickedBlock().getType() != Material.CHEST) + return; + + if (!_usedChests.containsKey(event.getPlayer())) + _usedChests.put(event.getPlayer(), new ArrayList<>()); + + ArrayList locs = _usedChests.get(event.getPlayer()); + + if (locs.contains(event.getClickedBlock().getLocation())) + return; + + locs.add(event.getClickedBlock().getLocation()); + + incrementQuests((Player) event.getPlayer(), 1, "Chest"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/CollectQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/CollectQuestTracker.java new file mode 100644 index 000000000..d8ad07885 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/CollectQuestTracker.java @@ -0,0 +1,119 @@ +package nautilus.game.arcade.quest; + +import java.util.ArrayList; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +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.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.events.ChestRefillEvent; +import nautilus.game.arcade.game.Game; + +/** + * CollectQuestTracker + * + * @author xXVevzZXx + */ +public class CollectQuestTracker extends QuestTracker +{ + private ArrayList _itemsAvailable = new ArrayList<>(); + private ArrayList _usedChests = new ArrayList<>(); + + public CollectQuestTracker(Game game) + { + super(game, TriggerType.COLLECT); + } + + @EventHandler(priority=EventPriority.LOWEST) + public void chestRefill(ChestRefillEvent event) + { + if (event.isCancelled()) + return; + + _usedChests.clear(); + } + + @EventHandler(priority=EventPriority.HIGHEST) + public void chestRegister(PlayerInteractEvent event) + { + if (!getGame().IsLive()) + return; + + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) + return; + + if (event.getClickedBlock().getType() != Material.CHEST) + return; + + if (_usedChests.contains(event.getClickedBlock().getLocation())) + return; + + Chest chest = (Chest) event.getClickedBlock().getState(); + + if (chest instanceof DoubleChest) + { + DoubleChest doubleChest = (DoubleChest) chest; + for (ItemStack item : doubleChest.getLeftSide().getInventory()) + { + if (item == null) + continue; + + _itemsAvailable.add(item); + } + for (ItemStack item : doubleChest.getRightSide().getInventory()) + { + if (item == null) + continue; + + _itemsAvailable.add(item); + } + } + else if (chest instanceof Chest) + { + for (ItemStack item : chest.getInventory()) + { + if (item == null) + continue; + + _itemsAvailable.add(item); + } + } + + _usedChests.add(event.getClickedBlock().getLocation()); + } + + @EventHandler + public void collectItem(InventoryClickEvent event) + { + if (!getGame().IsLive()) + return; + + if (event.getClickedInventory() instanceof PlayerInventory) + return; + + if (!_itemsAvailable.contains(event.getCurrentItem())) + return; + + _itemsAvailable.remove(event.getCurrentItem()); + + String item = event.getCurrentItem().getType().toString(); + + if (event.getCurrentItem().hasItemMeta()) + item = event.getCurrentItem().getItemMeta().getDisplayName(); + + incrementQuests((Player) event.getWhoClicked(), event.getCurrentItem().getAmount(), ChatColor.stripColor(item)); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillEntityQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillEntityQuestTracker.java new file mode 100644 index 000000000..7b99b9198 --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillEntityQuestTracker.java @@ -0,0 +1,51 @@ +package nautilus.game.arcade.quest; + +import net.md_5.bungee.api.ChatColor; + +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDeathEvent; + +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.Game; + +/** + * KillEntityQuestTracker + * + * @author xXVevzZXx + */ +public class KillEntityQuestTracker extends QuestTracker +{ + + public KillEntityQuestTracker(Game game) + { + super(game, TriggerType.KILL); + } + + @EventHandler + public void killEntity(EntityDeathEvent event) + { + if (!getGame().IsLive()) + return; + + LivingEntity lEntity = event.getEntity(); + + if (!(lEntity.getKiller() instanceof Player)) + return; + + Player player = lEntity.getKiller(); + + if (lEntity instanceof Player) + return; + + String name = lEntity.getType().getName(); + + if (lEntity.isCustomNameVisible()) + name = lEntity.getCustomName(); + + incrementQuests((Player) player, 1, ChatColor.stripColor(name), getGame().GetKit(player).GetName() + "Kit"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillQuestTracker.java new file mode 100644 index 000000000..ce071aecd --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/KillQuestTracker.java @@ -0,0 +1,44 @@ +package nautilus.game.arcade.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.quests.TriggerType; +import mineplex.minecraft.game.core.combat.event.CombatDeathEvent; + +import nautilus.game.arcade.game.Game; + +/** + * WInQuestTracker + * + * @author xXVevzZXx + */ +public class KillQuestTracker extends QuestTracker +{ + + public KillQuestTracker(Game game) + { + super(game, TriggerType.KILL); + } + + @EventHandler + public void onKill(CombatDeathEvent event) + { + if (!getGame().IsLive()) + return; + + if (event.GetLog().GetKiller() == null) + return; + + if (!event.GetLog().GetKiller().IsPlayer()) + return; + + Player player = UtilPlayer.searchExact(event.GetLog().GetKiller().GetName()); + if (player == null) + return; + + incrementQuests(player, 1, "Player", getGame().GetKit(player).GetName() + "Kit"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ParticipateQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ParticipateQuestTracker.java new file mode 100644 index 000000000..94af7fffe --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/ParticipateQuestTracker.java @@ -0,0 +1,37 @@ +package nautilus.game.arcade.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.UtilServer; +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.Arcade; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.Game.GameState; + +/** + * ParticipateQuestTracker + * + * @author xXVevzZXx + */ +public class ParticipateQuestTracker extends QuestTracker +{ + + public ParticipateQuestTracker(Game game) + { + super(game, TriggerType.COMPLETE); + } + + @EventHandler + public void completeGame(GameStateChangeEvent event) + { + if (event.GetState() != GameState.End) + return; + + for (Player player : getGame().GetPlayers(true)) + incrementQuests(player, 1, ((Arcade) UtilServer.getPlugin()).getServerConfig().getServerGroup().getPrefix(), getGame().GetKit(player).GetName() + "Kit"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/PlayGameQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/PlayGameQuestTracker.java new file mode 100644 index 000000000..b8d81a39e --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/PlayGameQuestTracker.java @@ -0,0 +1,37 @@ +package nautilus.game.arcade.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.UtilServer; +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.Arcade; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.Game.GameState; + +/** + * PlayGameQuestTracker + * + * @author xXVevzZXx + */ +public class PlayGameQuestTracker extends QuestTracker +{ + + public PlayGameQuestTracker(Game game) + { + super(game, TriggerType.PLAY); + } + + @EventHandler + public void gameStart(GameStateChangeEvent event) + { + if (event.GetState() != GameState.Live) + return; + + for (Player player : getGame().GetPlayers(true)) + incrementQuests(player, 1, ((Arcade) UtilServer.getPlugin()).getServerConfig().getServerGroup().getPrefix(), getGame().GetKit(player).GetName() + "Kit"); + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/QuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/QuestTracker.java new file mode 100644 index 000000000..c34a50efc --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/QuestTracker.java @@ -0,0 +1,99 @@ +package nautilus.game.arcade.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +import mineplex.core.quests.Quest; +import mineplex.core.quests.QuestClientData; +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.game.Game; + +/** + * QuestTracker + * + * @author xXVevzZXx + */ +public class QuestTracker implements Listener +{ + private T _game; + private TriggerType _trigger; + + public QuestTracker(T game, TriggerType type) + { + _game = game; + _trigger = type; + } + + public T getGame() + { + return _game; + } + + public boolean canProgressQuests() + { + return getGame().CanAddStats; + } + + public void incrementQuests(Player player, int value) + { + incrementQuests(player, value, ""); + } + + public void incrementQuests(Player player, int value, String... items) + { + if (canProgressQuests()) + { + for (Quest quest : getGame().getArcadeManager().getQuestManager().getAvailableQuests()) + { + if (!quest.isGeneral()) + { + if (getGame().GetType().getDisplay() != quest.getGame() && getGame().GetType().getDisplay().getGameCategory() != quest.getGameCategory()) + continue; + } + + if (quest.getTrigger() != _trigger) + continue; + + if (!quest.getItem()[0].equalsIgnoreCase("")) + { + boolean cont = true; + for (String questItem : quest.getItem()) + { + for (String str : items) + { + String first = str.replaceAll(" ", ""); + String compare = questItem.replaceAll(" ", ""); + + if (first.equalsIgnoreCase(compare)) + { + cont = false; + break; + } + else + { + cont = true; + } + } + } + + if (cont) + continue; + } + + QuestClientData data = _game.getArcadeManager().getQuestManager().Get(player); + if (!data.hasQuest(quest)) + continue; + + Quest toProgress = data.getQuest(quest.getID()); + + _game.getArcadeManager().getQuestManager().incrementQuest(player, toProgress, value); + } + } + } + + public TriggerType getTrigger() + { + return _trigger; + } +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/WinQuestTracker.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/WinQuestTracker.java new file mode 100644 index 000000000..283f405fd --- /dev/null +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/quest/WinQuestTracker.java @@ -0,0 +1,39 @@ +package nautilus.game.arcade.quest; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +import mineplex.core.common.util.UtilServer; +import mineplex.core.quests.TriggerType; + +import nautilus.game.arcade.Arcade; +import nautilus.game.arcade.events.GameStateChangeEvent; +import nautilus.game.arcade.game.Game; +import nautilus.game.arcade.game.Game.GameState; + +/** + * WinQuestTracker + * + * @author xXVevzZXx + */ +public class WinQuestTracker extends QuestTracker +{ + + public WinQuestTracker(Game game) + { + super(game, TriggerType.WIN); + } + + @EventHandler + public void onWin(GameStateChangeEvent event) + { + if (event.GetState() != GameState.End) + return; + + for (Player player : getGame().getWinners()) + { + incrementQuests(player, 1, ((Arcade) UtilServer.getPlugin()).getServerConfig().getServerGroup().getPrefix(), getGame().GetKit(player).GetName() + "Kit"); + } + } + +} diff --git a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/scoreboard/GameScoreboard.java b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/scoreboard/GameScoreboard.java index def71d516..e912a550b 100644 --- a/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/scoreboard/GameScoreboard.java +++ b/Plugins/Nautilus.Game.Arcade/src/nautilus/game/arcade/scoreboard/GameScoreboard.java @@ -29,10 +29,15 @@ public class GameScoreboard extends WritableMineplexScoreboard public GameScoreboard(Game game) { + this(game, null); + } + + public GameScoreboard(Game game, Player player) + { + super(player); + _game = game; - _title = " MINEPLEX "; - setSidebarName(C.Bold + _title); } diff --git a/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/modules/serverreset/ServerResetCommand.java b/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/modules/serverreset/ServerResetCommand.java index 8356e8fd6..d716ee669 100644 --- a/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/modules/serverreset/ServerResetCommand.java +++ b/Plugins/Nautilus.Game.PvP/src/nautilus/game/pvp/modules/serverreset/ServerResetCommand.java @@ -44,7 +44,7 @@ public class ServerResetCommand extends CommandBase clientEvent.GetClient().Game().SetEconomyBalance(0); } - File economyDir = new File("economy/"); + File economyDir = new File("shop/"); FilenameFilter statsFilter = new FilenameFilter() { diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java index 21104db46..9b8256d80 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/GemHunters.java @@ -1,13 +1,5 @@ package mineplex.gemhunters; -import net.minecraft.server.v1_8_R3.MinecraftServer; - -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.plugin.java.JavaPlugin; -import org.spigotmc.SpigotConfig; - import mineplex.core.CustomTagFix; import mineplex.core.FoodDupeFix; import mineplex.core.TimingsFix; @@ -65,6 +57,7 @@ import mineplex.core.task.TaskManager; import mineplex.core.teleport.Teleport; import mineplex.core.texttutorial.TextTutorialManager; import mineplex.core.thank.ThankManager; +import mineplex.core.titles.Titles; import mineplex.core.twofactor.TwoFactorAuth; import mineplex.core.updater.FileUpdater; import mineplex.core.updater.Updater; @@ -92,6 +85,7 @@ import mineplex.gemhunters.spawn.SpawnModule; import mineplex.gemhunters.supplydrop.SupplyDropModule; import mineplex.gemhunters.tutorial.GemHuntersTutorial; import mineplex.gemhunters.world.DebugListeners; +import mineplex.gemhunters.world.Leaderboards; import mineplex.gemhunters.world.TimeCycle; import mineplex.gemhunters.world.UndergroundMobs; import mineplex.gemhunters.world.WorldListeners; @@ -99,6 +93,12 @@ import mineplex.gemhunters.worldevent.WorldEventModule; import mineplex.minecraft.game.core.combat.CombatManager; import mineplex.minecraft.game.core.condition.ConditionManager; import mineplex.minecraft.game.core.damage.DamageManager; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.plugin.java.JavaPlugin; +import org.spigotmc.SpigotConfig; import static mineplex.core.Managers.require; @@ -186,6 +186,7 @@ public class GemHunters extends JavaPlugin // Creatures Creature creature = new Creature(this); + creature.SetDisableCustomDrops(true); // The old classic Damage Manager DamageManager damageManager = new DamageManager(this, new CombatManager(this), new NpcManager(this, creature), disguiseManager, new ConditionManager(this)); @@ -269,7 +270,9 @@ public class GemHunters extends JavaPlugin // Tutorials TextTutorialManager tutorialManager = new TextTutorialManager(this, donationManager, new TaskManager(this, clientManager)); tutorialManager.addTutorial(new GemHuntersTutorial()); - + + require(Titles.class).forceDisable(); + // Now we finally get to enable the Gem Hunters modules // Though if any other module needs one of these it will be generated in // order, however they are all here just for good measure. @@ -301,7 +304,8 @@ public class GemHunters extends JavaPlugin new WorldListeners(this); new TimeCycle(this); new UndergroundMobs(this); - new DebugListeners(this); + new DebugListeners(this); + new Leaderboards(); // UpdateEvent!!! new Updater(this); diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java index aa08bb811..03490754c 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/beta/BetaModule.java @@ -19,7 +19,8 @@ public class BetaModule extends MiniPlugin "Thank you for playing Gem Hunters!", "Safezones are marked as green areas on your map!", "Players that have super valuable items show up on your map!", - "Tell us what you want added next by voting on our features Trello! https://trello.com/b/ia1kjwcx" + "Tell us what you want added next by voting on our features Trello! https://trello.com/b/ia1kjwcx", + "The highest value player is shown on the map as a red pointer." }; private int _lastIndex; @@ -30,7 +31,7 @@ public class BetaModule extends MiniPlugin } @EventHandler - public void annouce(UpdateEvent event) + public void announce(UpdateEvent event) { if (event.getType() != UpdateType.MIN_01) { diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java index 02e210ff5..f53b1eb44 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/chat/ChatModule.java @@ -1,5 +1,7 @@ package mineplex.gemhunters.chat; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.progression.ProgressionModule; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -26,15 +28,19 @@ public class ChatModule extends MiniPlugin private final CoreClientManager _clientManager; private final Chat _chat; + private final EconomyModule _economy; private final PartyManager _party; - + private final ProgressionModule _progression; + private ChatModule() { super("Chat"); _clientManager = require(CoreClientManager.class); _chat = require(Chat.class); + _economy = require(EconomyModule.class); _party = require(PartyManager.class); + _progression = require(ProgressionModule.class); } @EventHandler(priority = EventPriority.LOWEST) @@ -90,7 +96,7 @@ public class ChatModule extends MiniPlugin } else { - message += C.cWhite; + message = _progression.getTitle(_economy.getGems(player)).getTitle() + " " + message + C.cWhite; } message += _chat.getFilteredMessage(player, event.getMessage()); diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java index 4f9baa634..367f5f5e8 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/death/DeathModule.java @@ -1,11 +1,20 @@ package mineplex.gemhunters.death; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - +import com.google.common.collect.Sets; +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.stats.StatsManager; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; +import mineplex.gemhunters.playerstatus.PlayerStatusModule; +import mineplex.gemhunters.playerstatus.PlayerStatusType; +import mineplex.gemhunters.spawn.SpawnModule; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; @@ -13,7 +22,6 @@ import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Entity; 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.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -22,25 +30,14 @@ import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerQuitEvent; -import com.google.common.collect.Sets; - -import mineplex.core.MiniPlugin; -import mineplex.core.ReflectivelyCreateMiniPlugin; -import mineplex.core.common.util.C; -import mineplex.core.common.util.UtilPlayer; -import mineplex.core.common.util.UtilServer; -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.gemhunters.death.event.PlayerCustomRespawnEvent; -import mineplex.gemhunters.playerstatus.PlayerStatusModule; -import mineplex.gemhunters.playerstatus.PlayerStatusType; -import mineplex.gemhunters.spawn.SpawnModule; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; /** * This module handles anything to do with a players death @@ -56,6 +53,7 @@ public class DeathModule extends MiniPlugin private static final int DEATH_ANIMATION_COUNTDOWN = 2000; private final PlayerStatusModule _playerStatus; + private final StatsManager _stats; private final SpawnModule _spawn; private final Map _toRemove; @@ -65,6 +63,7 @@ public class DeathModule extends MiniPlugin super("Death"); _playerStatus = require(PlayerStatusModule.class); + _stats = require(StatsManager.class); _spawn = require(SpawnModule.class); _toRemove = new HashMap<>(); @@ -80,6 +79,14 @@ public class DeathModule extends MiniPlugin player.setFoodLevel(20); player.setExhaustion(0); + // Record the stats + Player killer = player.getKiller(); + + if (killer != null) + { + _stats.incrementStat(killer, "Gem Hunters.Kills", 1); + } + startAnimation(player); _toRemove.put(player.getUniqueId(), System.currentTimeMillis()); } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java index c4d3b75d8..d64c059d3 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/CashOutModule.java @@ -3,14 +3,20 @@ package mineplex.gemhunters.economy; import mineplex.core.MiniPlugin; import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.common.currency.GlobalCurrency; -import mineplex.core.common.util.*; +import mineplex.core.common.util.C; +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilEvent; import mineplex.core.common.util.UtilEvent.ActionType; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilTextMiddle; import mineplex.core.donation.DonationManager; 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.core.stats.StatsManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import mineplex.gemhunters.economy.command.CashOutItemCommand; @@ -30,7 +36,12 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; import java.text.DecimalFormat; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.UUID; @ReflectivelyCreateMiniPlugin public class CashOutModule extends MiniPlugin @@ -44,7 +55,8 @@ public class CashOutModule extends MiniPlugin private static final int CASH_OUT_MAX_MOVE_DISTANCE_SQUARED = 4; private final DonationManager _donation; - + private final StatsManager _stats; + private final Map _sessions; private final Set _aboutToCashOut; @@ -53,7 +65,8 @@ public class CashOutModule extends MiniPlugin super("Cash Out"); _donation = require(DonationManager.class); - + _stats = require(StatsManager.class); + _sessions = new HashMap<>(); _aboutToCashOut = new HashSet<>(); } @@ -147,6 +160,11 @@ public class CashOutModule extends MiniPlugin _aboutToCashOut.add(player.getUniqueId()); + if (completeEvent.getGems() != EconomyModule.GEM_START_COST) + { + _stats.incrementStat(player, "Gem Hunters.GemsEarned", completeEvent.getGems()); + } + _donation.rewardCurrencyUntilSuccess(GlobalCurrency.GEM, player, "Earned", completeEvent.getGems()); session.endSession(); @@ -158,7 +176,7 @@ public class CashOutModule extends MiniPlugin } else { - Portal.getInstance().sendPlayerToGenericServer(player, GenericServer.BETA_HUB, Intent.FORCE_TRANSFER); + Portal.getInstance().sendPlayerToGenericServer(player, GenericServer.HUB, Intent.FORCE_TRANSFER); runSyncLater(() -> { diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java index 5ebb5e001..9fac54ea7 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/economy/EconomyModule.java @@ -1,12 +1,5 @@ package mineplex.gemhunters.economy; -import java.util.UUID; - -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.entity.PlayerDeathEvent; - import mineplex.core.MiniClientPlugin; import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.common.currency.GlobalCurrency; @@ -14,11 +7,16 @@ import mineplex.core.common.util.F; import mineplex.core.common.util.UtilServer; import mineplex.core.donation.DonationManager; import mineplex.core.donation.Donor; -import mineplex.gemhunters.death.event.PlayerCustomRespawnEvent; import mineplex.gemhunters.economy.command.GiveGemsCommand; import mineplex.gemhunters.economy.event.PlayerCashOutCompleteEvent; import mineplex.gemhunters.economy.event.PlayerEarnGemsEvent; import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.PlayerDeathEvent; + +import java.util.UUID; @ReflectivelyCreateMiniPlugin public class EconomyModule extends MiniClientPlugin @@ -29,6 +27,9 @@ public class EconomyModule extends MiniClientPlugin private final DonationManager _donation; + private Player _mostValuable; + private int _mostGems; + public EconomyModule() { super("Economy"); @@ -117,6 +118,23 @@ public class EconomyModule extends MiniClientPlugin return Get(player); } + @Override + protected void Set(Player player, Integer data) + { + super.Set(player, data); + + if (_mostValuable == null || _mostGems < data) + { + _mostValuable = player; + _mostGems = data; + } + } + + public Player getMostValuablePlayer() + { + return _mostValuable; + } + @Override protected Integer addPlayer(UUID uuid) { diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java index dbff05dc6..9aa42e3ac 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/LootModule.java @@ -2,9 +2,16 @@ package mineplex.gemhunters.loot; import mineplex.core.MiniPlugin; import mineplex.core.ReflectivelyCreateMiniPlugin; -import mineplex.core.common.util.*; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +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.UtilServer; +import mineplex.core.common.util.UtilTime; import mineplex.core.google.GoogleSheetsManager; +import mineplex.core.stats.StatsManager; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; import mineplex.gemhunters.economy.EconomyModule; @@ -14,7 +21,11 @@ import mineplex.gemhunters.loot.command.UpdateLootCommand; import mineplex.gemhunters.loot.deserialisers.ChestPropertiesDeserialiser; import mineplex.gemhunters.loot.deserialisers.LootItemDeserialiser; import mineplex.gemhunters.loot.event.PlayerChestOpenEvent; -import mineplex.gemhunters.loot.rewards.*; +import mineplex.gemhunters.loot.rewards.LootChestReward; +import mineplex.gemhunters.loot.rewards.LootGadgetReward; +import mineplex.gemhunters.loot.rewards.LootItemReward; +import mineplex.gemhunters.loot.rewards.LootRankReward; +import mineplex.gemhunters.loot.rewards.LootShardReward; import mineplex.gemhunters.safezone.SafezoneModule; import mineplex.gemhunters.spawn.event.PlayerTeleportIntoMapEvent; import mineplex.gemhunters.world.WorldDataModule; @@ -26,15 +37,25 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Chest; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; 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.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeUnit; @ReflectivelyCreateMiniPlugin @@ -58,6 +79,7 @@ public class LootModule extends MiniPlugin private final EconomyModule _economy; private final GoogleSheetsManager _sheets; private final SafezoneModule _safezone; + private final StatsManager _stats; private final WorldDataModule _worldData; private final Map> _chestLoot; @@ -73,6 +95,7 @@ public class LootModule extends MiniPlugin _economy = require(EconomyModule.class); _sheets = require(GoogleSheetsManager.class); _safezone = require(SafezoneModule.class); + _stats = require(StatsManager.class); _worldData = require(WorldDataModule.class); _chestLoot = new HashMap<>(); _chestProperties = new HashMap<>(); @@ -453,7 +476,8 @@ public class LootModule extends MiniPlugin event.setCancelled(true); return; } - + + _stats.incrementStat(player, "Gem Hunters.ChestsOpened", 1); fillChest(player, block, key); } @@ -475,10 +499,10 @@ public class LootModule extends MiniPlugin handleRewardItem((Player) event.getWhoClicked(), itemStack); } - @EventHandler + @EventHandler(priority = EventPriority.HIGH) public void pickupItem(PlayerPickupItemEvent event) { - if (event.getItem() == null) + if (event.getItem() == null || event.isCancelled()) { return; } @@ -622,10 +646,35 @@ public class LootModule extends MiniPlugin { LootItemReward reward = iterator.next(); - if (player.equals(reward.getPlayer()) && player.getInventory().contains(reward.getItemStack())) + if (reward.getPlayer() != null && player.equals(reward.getPlayer())) { reward.success(); iterator.remove(); + + for (Entity entity : reward.getPlayer().getWorld().getEntities()) + { + if (entity instanceof Item) + { + Item item = (Item) entity; + + if (item.getItemStack().getType() == reward.getItemStack().getType()) + { + entity.remove(); + } + } + } + } + } + } + + @EventHandler + public void playerDeath(PlayerDeathEvent event) + { + for (LootItemReward reward : _itemRewards) + { + if (reward.getPlayer().equals(event.getEntity())) + { + reward.death(event); } } } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java index f0ec11991..49acb3858 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/loot/rewards/LootItemReward.java @@ -38,7 +38,7 @@ public abstract class LootItemReward public final void collectItem(Player player) { - if (player.equals(_player)) + if (_player != null && player.equals(_player)) { return; } @@ -73,6 +73,7 @@ public abstract class LootItemReward public final void death(PlayerDeathEvent event) { + _player = null; } public boolean isFirstPickup() diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java index 09d4aca84..d191cf23c 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/map/ItemMapRenderer.java @@ -1,29 +1,24 @@ package mineplex.gemhunters.map; -import java.awt.Color; -import java.util.Set; -import java.util.UUID; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.map.MapCanvas; -import org.bukkit.map.MapCursor; -import org.bukkit.map.MapCursorCollection; -import org.bukkit.map.MapPalette; -import org.bukkit.map.MapRenderer; -import org.bukkit.map.MapView; - import mineplex.core.Managers; import mineplex.core.common.util.UtilTime; import mineplex.core.party.Party; import mineplex.core.party.PartyManager; +import mineplex.gemhunters.economy.EconomyModule; import mineplex.gemhunters.loot.LootModule; import mineplex.gemhunters.safezone.SafezoneModule; import mineplex.gemhunters.supplydrop.SupplyDrop; import mineplex.gemhunters.supplydrop.SupplyDropModule; import mineplex.gemhunters.worldevent.WorldEvent; import mineplex.gemhunters.worldevent.WorldEventModule; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.map.*; + +import java.awt.*; +import java.util.Set; +import java.util.UUID; /** * All item map code was adapted from Clans.
@@ -35,6 +30,7 @@ public class ItemMapRenderer extends MapRenderer private static final int STANDARD_Y = 70; private final ItemMapModule _itemMap; + private final EconomyModule _economy; private final LootModule _loot; private final SafezoneModule _safezone; private final SupplyDropModule _supply; @@ -47,6 +43,7 @@ public class ItemMapRenderer extends MapRenderer super(true); _itemMap = Managers.require(ItemMapModule.class); + _economy = Managers.require(EconomyModule.class); _loot = Managers.require(LootModule.class); _safezone = Managers.require(SafezoneModule.class); _supply = Managers.require(SupplyDropModule.class); @@ -273,6 +270,10 @@ public class ItemMapRenderer extends MapRenderer { cursorDisplay = MapCursor.Type.GREEN_POINTER; } + else if (other.equals(_economy.getMostValuablePlayer())) + { + cursorDisplay = MapCursor.Type.RED_POINTER; + } if (cursorDisplay == null) { diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionModule.java new file mode 100644 index 000000000..e99457acd --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionModule.java @@ -0,0 +1,41 @@ +package mineplex.gemhunters.progression; + +import mineplex.core.MiniPlugin; +import mineplex.core.ReflectivelyCreateMiniPlugin; +import mineplex.core.common.util.C; + +import java.util.Arrays; +import java.util.List; + +@ReflectivelyCreateMiniPlugin +public class ProgressionModule extends MiniPlugin +{ + + private static final List TITLE_LIST = Arrays.asList( + new ProgressionTitle(C.cGray + "Bankrupt", 0), + new ProgressionTitle(C.cAqua + "Beggar", 100), + new ProgressionTitle(C.cGreen + "Poor", 250), + new ProgressionTitle(C.cGreen + "MiddleClass", 500), + new ProgressionTitle(C.cGold + "Wealthy", 750), + new ProgressionTitle(C.cGold + "Loaded", 1000), + new ProgressionTitle(C.cRed + "Millionaire", 5000) + ); + + public ProgressionModule() + { + super("Progression"); + } + + public ProgressionTitle getTitle(int gems) + { + for (ProgressionTitle title : TITLE_LIST) + { + if (title.getRequiredGems() >= gems) + { + return title; + } + } + + return TITLE_LIST.get(TITLE_LIST.size() - 1); + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionTitle.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionTitle.java new file mode 100644 index 000000000..0e512e225 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/progression/ProgressionTitle.java @@ -0,0 +1,24 @@ +package mineplex.gemhunters.progression; + +public class ProgressionTitle +{ + + private String _title; + private int _requiredGems; + + public ProgressionTitle(String title, int requiredGems) + { + _title = title; + _requiredGems = requiredGems; + } + + public String getTitle() + { + return _title; + } + + public int getRequiredGems() + { + return _requiredGems; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java index da43ba06c..305b1f9c8 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/quest/QuestModule.java @@ -5,6 +5,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import mineplex.core.common.util.*; +import mineplex.core.stats.StatsManager; import net.md_5.bungee.api.ChatColor; import org.bukkit.Bukkit; @@ -87,6 +88,7 @@ public class QuestModule extends MiniClientPlugin }; private final EconomyModule _economy; + private final StatsManager _stats; private final WorldDataModule _worldData; private QuestModule() @@ -94,6 +96,7 @@ public class QuestModule extends MiniClientPlugin super("Quest"); _economy = require(EconomyModule.class); + _stats = require(StatsManager.class); _worldData = require(WorldDataModule.class); Menu menu = new QuestUI(this); @@ -311,7 +314,9 @@ public class QuestModule extends MiniClientPlugin } player.sendMessage(F.main(_moduleName, "Completed " + F.name(quest.getName()) + ".")); - + + _stats.incrementStat(player, "Gem Hunters.QuestsCompleted", 1); + QuestPlayerData playerData = Get(player); playerData.getActiveQuests().remove(Integer.valueOf(quest.getId())); playerData.getCompletedQuests().add(quest.getId()); diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java index 627581b5b..22dc510c5 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/safezone/SafezoneModule.java @@ -9,6 +9,7 @@ import mineplex.core.recharge.Recharge; import mineplex.gemhunters.death.event.QuitNPCSpawnEvent; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -18,6 +19,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerQuitEvent; import mineplex.core.MiniPlugin; @@ -212,6 +214,17 @@ public class SafezoneModule extends MiniPlugin } } + @EventHandler + public void flintAndSteelInteract(PlayerInteractEvent event) + { + if (event.getItem() == null || event.getItem().getType() != Material.FLINT_AND_STEEL || event.getClickedBlock() == null || !isInSafeZone(event.getClickedBlock().getLocation())) + { + return; + } + + event.setCancelled(true); + } + public boolean isInSafeZone(HumanEntity player) { return isInSafeZone(player.getLocation()) && _playerStatus.Get((Player) player).getStatusType() != PlayerStatusType.COMBAT; diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java index 27e0eb487..ba3067ae3 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/GemHuntersScoreboard.java @@ -1,5 +1,7 @@ package mineplex.gemhunters.scoreboard; +import mineplex.gemhunters.progression.ProgressionModule; +import mineplex.gemhunters.progression.ProgressionTitle; import org.bukkit.entity.Player; import mineplex.core.Managers; @@ -17,6 +19,7 @@ public class GemHuntersScoreboard extends WritableMineplexScoreboard private final EconomyModule _economy; private final PlayerStatusModule _playerStatus; + private final ProgressionModule _progression; private final SupplyDropModule _supplyDrop; public GemHuntersScoreboard(Player player) @@ -25,6 +28,7 @@ public class GemHuntersScoreboard extends WritableMineplexScoreboard _economy = Managers.get(EconomyModule.class); _playerStatus = Managers.get(PlayerStatusModule.class); + _progression = Managers.get(ProgressionModule.class); _supplyDrop = Managers.get(SupplyDropModule.class); } @@ -60,4 +64,9 @@ public class GemHuntersScoreboard extends WritableMineplexScoreboard { return _economy.getGems(player); } + + public String getPrefix(Player perspective, Player subject) + { + return _progression.getTitle(_economy.getGems(subject)).getTitle() + " " + C.cYellow; + } } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java index 4b10288c0..6b6e90b27 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/scoreboard/ScoreboardModule.java @@ -70,17 +70,17 @@ public class ScoreboardModule extends MiniPlugin for (Player player : Bukkit.getOnlinePlayers()) { int gems = _economy.getGems(player); - + for (GemHuntersScoreboard scoreboard : _scoreboards.values()) { Objective objective = scoreboard.getHandle().getObjective(DisplaySlot.BELOW_NAME); Score score = objective.getScore(player.getName()); - + if (score.getScore() == gems) { continue; } - + score.setScore(gems); } } @@ -106,45 +106,75 @@ public class ScoreboardModule extends MiniPlugin _scoreboards.remove(player.getUniqueId()); } - public void createPlayerScoreboard(Player player) - { - if (!_scoreboards.containsKey(player.getUniqueId())) + @EventHandler + public void updateScoreboard(UpdateEvent event) + { + if (event.getType() != UpdateType.SEC_20) { - GemHuntersScoreboard scoreboard = new GemHuntersScoreboard(player); - Scoreboard handle = scoreboard.getHandle(); + return; + } + for (Player player : Bukkit.getOnlinePlayers()) + { + createPlayerScoreboard(player); + } + } + + public void createPlayerScoreboard(Player player) + { + GemHuntersScoreboard scoreboard; + + if (_scoreboards.containsKey(player.getUniqueId())) + { + scoreboard = _scoreboards.get(player.getUniqueId()); + } + else + { + scoreboard = new GemHuntersScoreboard(player); _scoreboards.put(player.getUniqueId(), scoreboard); // Gem Counter Undername - Objective gemCounter = handle.registerNewObjective("Gems", "Gems"); + Objective gemCounter = scoreboard.getHandle().registerNewObjective("Gems", "Gems"); gemCounter.setDisplaySlot(DisplaySlot.BELOW_NAME); + } - for (GemHuntersScoreboard other : _scoreboards.values()) + Scoreboard handle = scoreboard.getHandle(); + + for (GemHuntersScoreboard other : _scoreboards.values()) + { + // Set the other player's name tag for the player joining + Player otherPlayer = other.getOwner(); + Team team = handle.getTeam(otherPlayer.getName()); + + if (team == null) { - // Set the other player's name tag for the player joining - Player otherPlayer = other.getOwner(); - Team team = handle.registerNewTeam(otherPlayer.getName()); - - team.setPrefix(C.cYellow); - //team.setSuffix(scoreboard.getSuffix(player, otherPlayer)); - team.addEntry(otherPlayer.getName()); - - if (player.equals(otherPlayer)) - { - continue; - } - - // Set the player that is joining - Scoreboard otherHandle = other.getHandle(); - Team otherTeam = otherHandle.registerNewTeam(player.getName()); - - otherTeam.setPrefix(C.cYellow); - //otherTeam.setSuffix(other.getSuffix(other.getOwner(), player)); - otherTeam.addEntry(player.getName()); + team = handle.registerNewTeam(otherPlayer.getName()); } - player.setScoreboard(scoreboard.getHandle()); + team.setPrefix(scoreboard.getPrefix(player, otherPlayer)); + //team.setSuffix(scoreboard.getSuffix(player, otherPlayer)); + team.addEntry(otherPlayer.getName()); + + if (player.equals(otherPlayer)) + { + continue; + } + + // Set the player that is joining + Scoreboard otherHandle = other.getHandle(); + Team otherTeam = otherHandle.getTeam(player.getName()); + + if (otherTeam == null) + { + otherTeam = otherHandle.registerNewTeam(player.getName()); + } + + otherTeam.setPrefix(other.getPrefix(other.getOwner(), player)); + //otherTeam.setSuffix(other.getSuffix(other.getOwner(), player)); + otherTeam.addEntry(player.getName()); } + + player.setScoreboard(handle); } public void updateTitles() diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java index 2f8725d8d..f647b4e18 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java @@ -199,7 +199,7 @@ public class ShopModule extends MiniPlugin String name = NAMES[UtilMath.r(NAMES.length)]; - name = (properties.isSelling() ? C.cGold + "Buying" : C.cGreen + "Selling") + C.cGray + " - " + C.cWhite + name; + name = (properties.isSelling() ? C.cGold + "Buy" : C.cGreen + "Sell") + C.cGray + " - " + C.cWhite + name; //DebugModule.getInstance().d("Trader at " + UtilWorld.locToStrClean(randomLocation) + " with key=" + key + " and index=" + index + " and max=" + spawned + "/" + max); if (properties.isSelling()) diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java index b1802129a..6b1e7fda7 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/spawn/SpawnModule.java @@ -140,7 +140,7 @@ public class SpawnModule extends MiniPlugin new SimpleNPC(_plugin, location, Villager.class, C.cGoldB + "Return To Hub", clicker -> { - Portal.getInstance().sendPlayerToGenericServer(clicker, GenericServer.BETA_HUB, Intent.PLAYER_REQUEST); + Portal.getInstance().sendPlayerToGenericServer(clicker, GenericServer.HUB, Intent.PLAYER_REQUEST); }); } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/Leaderboards.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/Leaderboards.java new file mode 100644 index 000000000..5ef1793f0 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/world/Leaderboards.java @@ -0,0 +1,33 @@ +package mineplex.gemhunters.world; + +import mineplex.core.Managers; +import mineplex.core.common.Pair; +import mineplex.core.common.util.UtilServer; +import mineplex.core.leaderboard.Leaderboard; +import mineplex.core.leaderboard.LeaderboardManager; +import mineplex.core.leaderboard.LeaderboardRepository.LeaderboardSQLType; + +public class Leaderboards +{ + + private final LeaderboardManager _manager; + private final WorldDataModule _worldData; + + public Leaderboards() + { + _manager = Managers.require(LeaderboardManager.class); + _worldData = Managers.require(WorldDataModule.class); + + // Make sure the world is loaded + UtilServer.runSyncLater(this::createLeaderboards, 20); + } + + private void createLeaderboards() + { + _manager.registerLeaderboard("TOP_GEM_HUNTERS_KILLS", new Leaderboard("Top Kills", Pair.create("Kill", "Kills"), new String[] {"Gem Hunters.Kills"}, LeaderboardSQLType.ALL, _worldData.getCustomLocation("TOP_KILLS").get(0), 10)); + _manager.registerLeaderboard("TOP_GEM_HUNTERS_DAILY_KILLS", new Leaderboard("Top Daily Kills", Pair.create("Kill", "Kills"), new String[] {"Gem Hunters.Kills"}, LeaderboardSQLType.DAILY, _worldData.getCustomLocation("TOP_DAILY_KILLS").get(0), 10)); + _manager.registerLeaderboard("TOP_GEM_HUNTERS_GEMS", new Leaderboard("Top Gems Cashed Out", Pair.create("Gem", "Gems"), new String[] {"Gem Hunters.GemsEarned"}, LeaderboardSQLType.ALL, _worldData.getCustomLocation("TOP_GEMS").get(0), 10)); + _manager.registerLeaderboard("TOP_GEM_HUNTERS_DAILY_GEMS", new Leaderboard("Top Daily Gems Cashed Out", Pair.create("Gem", "Gems"), new String[] {"Gem Hunters.GemsEarned"}, LeaderboardSQLType.DAILY, _worldData.getCustomLocation("TOP_DAILY_GEMS").get(0), 10)); + } +} + diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java index 2e16bbab7..cc81c84cc 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventModule.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import mineplex.gemhunters.worldevent.ufo.UFOWorldEvent; import org.bukkit.event.EventHandler; import mineplex.core.MiniPlugin; @@ -45,7 +46,8 @@ public class WorldEventModule extends MiniPlugin new BlizzardWorldEvent(), //new NetherPortalWorldEvent(), new WitherWorldEvent(), - new GwenMartWorldEvent() + new GwenMartWorldEvent(), + new UFOWorldEvent() ); } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java index 670084763..32dbd527c 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/WorldEventType.java @@ -8,14 +8,15 @@ public enum WorldEventType NETHER("Dark Portal", WorldEventPriority.TRIGGERED), WITHER("Wither Temple", WorldEventPriority.TRIGGERED), GWEN_MART("Gwen-Mart Mega Sale", WorldEventPriority.GLOBAL), - + UFO("UFO", WorldEventPriority.GLOBAL), + ; private String _name; private WorldEventPriority _priority; private long _last; - private WorldEventType(String name, WorldEventPriority priority) + WorldEventType(String name, WorldEventPriority priority) { _name = name; _priority = priority; diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/ufo/UFOWorldEvent.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/ufo/UFOWorldEvent.java new file mode 100644 index 000000000..871edf360 --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/worldevent/ufo/UFOWorldEvent.java @@ -0,0 +1,204 @@ +package mineplex.gemhunters.worldevent.ufo; + +import mineplex.core.Managers; +import mineplex.core.common.block.schematic.Schematic; +import mineplex.core.common.block.schematic.SchematicData; +import mineplex.core.common.block.schematic.UtilSchematic; +import mineplex.core.common.skin.SkinData; +import mineplex.core.common.util.C; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilTime; +import mineplex.core.utils.UtilVariant; +import mineplex.gemhunters.economy.EconomyModule; +import mineplex.gemhunters.loot.LootModule; +import mineplex.gemhunters.loot.rewards.LootChestReward; +import mineplex.gemhunters.worldevent.WorldEvent; +import mineplex.gemhunters.worldevent.WorldEventState; +import mineplex.gemhunters.worldevent.WorldEventType; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityCombustEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.BlockVector; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class UFOWorldEvent extends WorldEvent +{ + + private static final String SCHEMATIC_PATH = ".." + File.separator + ".." + File.separator + "update" + File.separator + "files" + File.separator + "UFO.schematic"; + private static final long MAX_TIME = TimeUnit.MINUTES.toMillis(10); + private static final ItemStack HELMET = new ItemStack(Material.GLASS); + private static final ItemStack SWORD = new ItemStack(Material.STONE_SWORD); + private static final ItemStack SWORD_LEADER = new ItemStack(Material.IRON_SWORD); + private static final long CASH_OUT_DELAY = TimeUnit.MINUTES.toMillis(10); + + private final EconomyModule _economy; + private final LootModule _loot; + + private Skeleton _leader; + private Set _skeletons; + private Set _ufoBlocks; + + public UFOWorldEvent() + { + super(WorldEventType.UFO); + + _economy = Managers.require(EconomyModule.class); + _loot = Managers.require(LootModule.class); + + _skeletons = new HashSet<>(); + _ufoBlocks = new HashSet<>(); + } + + @Override + public void onStart() + { + Location location = UtilAlg.Random(_worldData.getCustomLocation("NETHER_PORTAL")).clone().subtract(5, -10, 5); + Schematic schematic; + + try + { + schematic = UtilSchematic.loadSchematic(new File(SCHEMATIC_PATH)); + } + catch (IOException e) + { + e.printStackTrace(); + return; + } + + SchematicData data = schematic.paste(location, false, false, false); + + for (BlockVector vector : data.getBlocks()) + { + Location block = location.add(vector); + + _ufoBlocks.add(block.getBlock()); + + location.subtract(vector); + } + + _leader = UtilVariant.spawnWitherSkeleton(location); + _leader.setMaxHealth(200); + _leader.setHealth(_leader.getMaxHealth()); + _leader.getEquipment().setItemInHand(SWORD_LEADER); + _leader.setCustomName(C.cDGreenB + "Alien Leader"); + prepareSkeleton(_leader); + + for (int i = 0; i < 10; i++) + { + Skeleton skeleton = _leader.getWorld().spawn(location, Skeleton.class); + skeleton.getEquipment().setItemInHand(SWORD); + skeleton.setCustomName(C.cGreenB + "Alien"); + prepareSkeleton(skeleton); + _skeletons.add(skeleton); + } + + setEventState(WorldEventState.LIVE); + } + + private void prepareSkeleton(Skeleton skeleton) + { + skeleton.getEquipment().setHelmet(HELMET); + skeleton.setRemoveWhenFarAway(false); + skeleton.setCustomNameVisible(true); + } + + @EventHandler + public void entityDeath(EntityDeathEvent event) + { + LivingEntity entity = event.getEntity(); + + if (_skeletons.remove(entity)) + { + event.getDrops().clear(); + event.setDroppedExp(0); + + Player killer = entity.getKiller(); + + if (killer != null) + { + _economy.addToStore(killer, "Killing an Alien", 10); + } + } + + if (_leader != null && _leader.equals(entity)) + { + Player killer = _leader.getKiller(); + + if (killer != null) + { + ItemStack itemStack = SkinData.OMEGA_CHEST.getSkull(C.cAqua + "Omega Chest", new ArrayList<>()); + LootChestReward reward = new LootChestReward(CASH_OUT_DELAY, itemStack, "Omega", 1); + _leader.getWorld().dropItemNaturally(_leader.getEyeLocation(), itemStack); + _loot.addItemReward(reward); + _economy.addToStore(killer, "Killing The Alien Leader", 1000); + } + } + } + + @EventHandler + public void entityDamage(EntityCombustEvent event) + { + Entity entity = event.getEntity(); + + if (entity.equals(_leader) || _skeletons.contains(entity)) + { + event.setCancelled(true); + } + } + + @Override + public boolean checkToEnd() + { + return _leader.isDead() || UtilTime.elapsed(_start, MAX_TIME); + } + + @Override + public void onEnd() + { + _leader.remove(); + + for (Skeleton skeleton : _skeletons) + { + skeleton.remove(); + } + + _skeletons.clear(); + + for (Block block : _ufoBlocks) + { + block.setType(Material.AIR); + } + + _ufoBlocks.clear(); + } + + @Override + public Location[] getEventLocations() + { + return new Location[]{_leader.getLocation()}; + } + + @Override + public double getProgress() + { + return _leader.getHealth() / _leader.getMaxHealth(); + } +} diff --git a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java index 953d4be08..665bf33fd 100644 --- a/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java +++ b/Plugins/mineplex-google-sheets/src/mineplex/googlesheets/SpreadsheetType.java @@ -8,6 +8,7 @@ public enum SpreadsheetType GEM_HUNTERS_CHESTS("11Noztgbpu_gUKkc5F4evKKfyxS-Jv1coE0IrBToX_gg"), GEM_HUNTERS_SHOP("1OcYktxVZaW6Fm29Zh6w4Lb-UVyuN8r1x-TFb_3USYYI"), + QUESTS_SHEET("1Gy1a7GCVopmOLwYE3Sk1DNVCAIwT8ReaLu4wRe0sfDE"), SMASH_KITS("1Z_SLBzjiIVqu25PMGw9TwNKR3wd9Y9sX7rSDBl_rpxk") ; @@ -22,5 +23,4 @@ public enum SpreadsheetType { return _id; } - -} +} \ No newline at end of file diff --git a/Plugins/mineplex-questmanager/pom.xml b/Plugins/mineplex-questmanager/pom.xml new file mode 100644 index 000000000..49a9fd32c --- /dev/null +++ b/Plugins/mineplex-questmanager/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + com.mineplex + mineplex-parent + dev-SNAPSHOT + + mineplex-questmanager + Mineplex.questmanager + A centralized service that selects daily quests + + + 18.0 + 2.12 + 1.8.8-1.9-SNAPSHOT + + + + + ${project.groupId} + mineplex-serverdata + ${project.version} + + + com.google.guava + guava + ${version.guava} + compile + + + jline + jline + ${version.jline} + compile + + + com.mineplex + spigot + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + false + + + mineplex.quest.daemon.QuestDaemon + + + + + + package + + shade + + + + + + + \ No newline at end of file diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/client/RedisQuestSupplier.java b/Plugins/mineplex-questmanager/src/mineplex/quest/client/RedisQuestSupplier.java new file mode 100644 index 000000000..127862a66 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/client/RedisQuestSupplier.java @@ -0,0 +1,111 @@ +package mineplex.quest.client; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.bukkit.plugin.java.JavaPlugin; + +import com.google.common.collect.ImmutableSet; + +import mineplex.quest.client.event.QuestsUpdatedEvent; +import mineplex.quest.common.Quest; +import mineplex.quest.common.QuestSupplier; +import mineplex.quest.common.redis.PubSubChannels; +import mineplex.quest.common.redis.QuestTypeSerializer; +import mineplex.serverdata.redis.messaging.PubSubMessager; + +/** + * Provides methods to retrieve currently active quests. Retrieves active quests from the + * centralized quest service via redis. + *

+ * Intended to be thread-safe. + */ +public class RedisQuestSupplier implements QuestSupplier +{ + + private final JavaPlugin _plugin; + private final String _serverUniqueId; + private final PubSubMessager _pubSub; + private final ReadWriteLock _lock = new ReentrantReadWriteLock(); + + private final Set _quests = new HashSet<>(); + + public RedisQuestSupplier(JavaPlugin plugin, PubSubMessager pubSub) + { + _plugin = plugin; + _pubSub = pubSub; + + _serverUniqueId = plugin.getConfig().getString("serverstatus.name"); + + // update quests sent specifically to this server when it requests them (like on startup) + _pubSub.subscribe(PubSubChannels.QUEST_REQUEST_BASE + _serverUniqueId, this::updateQuests); + + requestActiveQuests(); + + // update quests when received + _pubSub.subscribe(PubSubChannels.QUEST_SUPPLIER_CHANNEL, this::updateQuests); + } + + private void updateQuests(String channel, String message) + { + _lock.writeLock().lock(); + try + { + _quests.clear(); + _quests.addAll(deserialize(message)); + + System.out.println("[QUEST-SUPPLIER] Quest update received from daemon, active quests: "); + _quests.forEach(q -> System.out.println("[QUEST-SUPPLIER] " + q.toString())); + + // notify + _plugin.getServer().getPluginManager().callEvent(new QuestsUpdatedEvent(get())); + } + finally + { + _lock.writeLock().unlock(); + } + } + + private Set deserialize(String json) + { + return QuestTypeSerializer.QUEST_GSON.fromJson(json, QuestTypeSerializer.QUEST_TYPE); + } + + private void requestActiveQuests() + { + System.out.println("[QUEST-SUPPLIER] Requesting active quests from QuestDaemon"); + // request current active quests, send server unique id so we can send a response just to this server + _pubSub.publish(PubSubChannels.QUEST_REQUEST_BASE, _serverUniqueId); + } + + @Override + public Set get() + { + _lock.readLock().lock(); + try + { + return ImmutableSet.copyOf(_quests); + } + finally + { + _lock.readLock().unlock(); + } + } + + @Override + public Optional getById(int uniquePersistentId) + { + _lock.readLock().lock(); + try + { + return _quests.stream().filter(q -> q.getUniqueId() == uniquePersistentId).findFirst(); + } + finally + { + _lock.readLock().unlock(); + } + } +} \ No newline at end of file diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/client/event/QuestsUpdatedEvent.java b/Plugins/mineplex-questmanager/src/mineplex/quest/client/event/QuestsUpdatedEvent.java new file mode 100644 index 000000000..82b70450a --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/client/event/QuestsUpdatedEvent.java @@ -0,0 +1,44 @@ +package mineplex.quest.client.event; + +import java.util.Set; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import mineplex.quest.common.Quest; + +/** + * An event called when the currently active quests are rotated at the end of a day. + */ +public class QuestsUpdatedEvent extends Event +{ + + private static final HandlerList HANDLERS = new HandlerList(); + + private final Set _to; + + public QuestsUpdatedEvent(Set to) + { + _to = to; + } + + /** + * @return The currently active quests. + */ + public Set getActiveQuests() + { + return _to; + } + + @Override + public HandlerList getHandlers() + { + return HANDLERS; + } + + public static HandlerList getHandlerList() + { + return HANDLERS; + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/BaseQuest.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/BaseQuest.java new file mode 100644 index 000000000..afc387d3a --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/BaseQuest.java @@ -0,0 +1,59 @@ +package mineplex.quest.common; + +/** + * Implementation of baseline {@link Quest}. + */ +public class BaseQuest implements Quest +{ + + private final int _uniqueId; + private final String _name; + private final QuestRarity _rarity; + private final int _cost; + + public BaseQuest(int uniqueId, String name, int cost, QuestRarity rarity) + { + _uniqueId = uniqueId; + _name = name; + _cost = cost; + _rarity = rarity; + } + + @Override + public String getName() + { + return _name; + } + + @Override + public int getUniqueId() + { + return _uniqueId; + } + + @Override + public QuestRarity getRarity() + { + return _rarity; + } + + @Override + public String getDataId() + { + return _uniqueId + ""; + } + + @Override + public boolean shouldRotate() + { + return _cost != -1; + } + + @Override + public String toString() + { + return "BaseQuest [uniqueId=" + _uniqueId + ", name=" + _name + ", rarity=" + _rarity + + ", cost=" + _cost + "]"; + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quest.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quest.java new file mode 100644 index 000000000..f2c7ac799 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quest.java @@ -0,0 +1,53 @@ +package mineplex.quest.common; + +import mineplex.quest.daemon.QuestManager; +import mineplex.serverdata.data.Data; +import mineplex.serverdata.data.DataRepository; + +/** + * A quest that can be completed by users for a reward. + */ +public interface Quest extends Data +{ + /** + * Gets the name of this quest. + * + * @return The name of this quest. + */ + String getName(); + + /** + * Gets the unique persistent id for this quest. This id will be used to store quests per user + * and should not be changed. + * + * @return The unique persistent id for this quest. + */ + int getUniqueId(); + + /** + * Gets the {@link QuestRarity} of this quest. + * + * @return The rarity of this quest. + */ + QuestRarity getRarity(); + + /** + * Get the unique persistent id for this quest as a String. Intended to be used for storage + * within Redis via {@link DataRepository}. + *

+ * Don't use this to get the quest unique id, use {@link Quest#getUniqueId()} instead. + * + * @return A string version of the unique persistent id for this quest. + */ + @Override + String getDataId(); + + /** + * Checks whether this quest should be selected by the {@link QuestManager} daemon process. + * Quests with a cost of -1 should not ever be selected as active quests by the daemon. + * + * @return true if this quest should be selected as an active quest, or + * false otherwise. + */ + boolean shouldRotate(); +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestRarity.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestRarity.java new file mode 100644 index 000000000..4ef625ee0 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestRarity.java @@ -0,0 +1,24 @@ +package mineplex.quest.common; + +/** + * How rare a quest is. In other words, how often this quest should be chosen. + */ +public enum QuestRarity +{ + COMMON(1.0), + RARE(0.5), + LEGENDARY(0.1) + ; + + private final double _weight; + + private QuestRarity(double weight) + { + _weight = weight; + } + + public double getWeight() + { + return _weight; + } +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestSupplier.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestSupplier.java new file mode 100644 index 000000000..9e32a2d80 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/QuestSupplier.java @@ -0,0 +1,29 @@ +package mineplex.quest.common; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +/** + * Provides access to {@link Quest}s tracked by this QuestManager. + */ +public interface QuestSupplier extends Supplier> +{ + + /** + * Get an immutable set containing all of the currently active quests. + */ + @Override + Set get(); + + /** + * Attempts to get the {@link Quest} matching the supplied persistent id. + * + * @param uniquePersistentId The unique id of the quest. + * + * @return An {@link Optional} describing the {@link Quest}, or an empty Optional if none is + * found. + */ + Optional getById(int uniquePersistentId); + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quests.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quests.java new file mode 100644 index 000000000..1b1bd41dd --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/Quests.java @@ -0,0 +1,73 @@ +package mineplex.quest.common; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +import mineplex.quest.common.util.UtilGoogleSheet; +import mineplex.quest.daemon.QuestDaemon; + +/** + * Provides access to all quests. + *

+ * Loads quests from a google sheets json file. + */ +public class Quests +{ + + private static final String ALL_QUESTS_FILE = "QUESTS_SHEET"; + private static final String QUEST_SHEET_KEY = "Quests"; + + private static final int UNIQUE_ID_COLUMN = 0; + private static final int NAME_COLUMN = 1; + private static final int COST_COLUMN = 4; + private static final int RARITY_COLUMN = 9; + + public static final Set QUESTS; + + static + { + ImmutableSet.Builder builder = ImmutableSet.builder(); + + Map>> sheets = UtilGoogleSheet.getSheetData(ALL_QUESTS_FILE); + + List> rows = sheets.getOrDefault(QUEST_SHEET_KEY, Collections.emptyList()); + + // get each row of spreadsheet, start at 1 since row 0 contains headers + for (int i = 1; i < rows.size(); i++) + { + List row = rows.get(i); + + // attempt to parse quest data we need + try + { + int uniqueId = Integer.parseInt(row.get(UNIQUE_ID_COLUMN)); + String name = row.get(NAME_COLUMN); + int cost = Integer.parseInt(row.get(COST_COLUMN)); + QuestRarity rarity = QuestRarity.valueOf(row.get(RARITY_COLUMN).toUpperCase()); + + Quest quest = new BaseQuest(uniqueId, name, cost, rarity); + + builder.add(quest); + } + catch (Exception e) + { + QuestDaemon.log("Exception encountered while parsing quest sheet row: " + row + ", " + + e.getMessage()); + e.printStackTrace(); + } + } + + QUESTS = builder.build(); + } + + public static Optional fromId(int uniqueId) + { + return QUESTS.stream().filter(quest -> quest.getUniqueId() == uniqueId).findFirst(); + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/PubSubChannels.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/PubSubChannels.java new file mode 100644 index 000000000..f28490ec8 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/PubSubChannels.java @@ -0,0 +1,13 @@ +package mineplex.quest.common.redis; + +/** + * Provides constants for Quests redis pub sub channels. + */ +public class PubSubChannels +{ + + public static final String QUEST_SUPPLIER_CHANNEL = "quest-manager"; + + public static final String QUEST_REQUEST_BASE = "quest-manager-request:"; + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestRedisDataRepository.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestRedisDataRepository.java new file mode 100644 index 000000000..825c1364e --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestRedisDataRepository.java @@ -0,0 +1,39 @@ +package mineplex.quest.common.redis; + +import mineplex.quest.common.Quest; +import mineplex.quest.common.Quests; +import mineplex.serverdata.Region; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ConnectionData; + +/** + * A {@link RedisDataRepository} that can serialize & deserialize (and thus store & retrieve from + * redis) Quest instances. + */ +public class QuestRedisDataRepository extends RedisDataRepository +{ + + public QuestRedisDataRepository(ConnectionData writeConn, ConnectionData readConn, Region region, + String elementLabel) + { + super(writeConn, readConn, region, Quest.class, elementLabel); + } + + @Override + protected Quest deserialize(String json) + { + if (json == null || json.isEmpty()) + { + return null; + } + + return Quests.fromId(Integer.parseInt(json)).orElse(null); + } + + @Override + protected String serialize(Quest quest) + { + return quest.getDataId(); + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeDeserialiazer.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeDeserialiazer.java new file mode 100644 index 000000000..4b71efc77 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeDeserialiazer.java @@ -0,0 +1,36 @@ +package mineplex.quest.common.redis; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import mineplex.quest.common.Quest; +import mineplex.quest.common.Quests; + +/** + * An implementation of a {@link JsonDeserializer} intended for use in {@link Gson}. Deserializes a + * {@link JsonElement} String into a Set. + */ +public class QuestTypeDeserialiazer implements JsonDeserializer> +{ + + @Override + public Set deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException + { + String[] split = json.getAsString().split(QuestTypeSerializer.SEPARATOR); + return Arrays.stream(split).map(questId -> Quests.fromId(Integer.valueOf(questId))) + .filter(Optional::isPresent).map(Optional::get) + .collect(Collectors.toCollection(HashSet::new)); + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeSerializer.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeSerializer.java new file mode 100644 index 000000000..67905f1a2 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/redis/QuestTypeSerializer.java @@ -0,0 +1,44 @@ +package mineplex.quest.common.redis; + +import java.lang.reflect.Type; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.common.base.Joiner; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import mineplex.quest.common.Quest; + +/** + * An implementation of a {@link JsonSerializer} intended for use in {@link Gson}. Serializes a + * Set into a {@link JsonElement} String. + */ +public class QuestTypeSerializer implements JsonSerializer> +{ + + @SuppressWarnings("serial") + public static final Type QUEST_TYPE = new TypeToken>(){}.getType(); + + public static final Gson QUEST_GSON = new GsonBuilder() + .registerTypeAdapter(QuestTypeSerializer.QUEST_TYPE, new QuestTypeDeserialiazer()) + .registerTypeAdapter(QuestTypeSerializer.QUEST_TYPE, new QuestTypeSerializer()) + .create(); + + public static final String SEPARATOR = ","; + + @Override + public JsonElement serialize(Set src, Type typeOfSrc, JsonSerializationContext context) + { + StringBuilder builder = new StringBuilder(); + Joiner.on(SEPARATOR).appendTo(builder, + src.stream().map(Quest::getDataId).collect(Collectors.toSet())); + return new JsonPrimitive(builder.toString()); + } + +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/RandomCollection.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/RandomCollection.java new file mode 100644 index 000000000..c74225c91 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/RandomCollection.java @@ -0,0 +1,62 @@ +package mineplex.quest.common.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Random; +import java.util.TreeMap; +import java.util.concurrent.ThreadLocalRandom; + +/** + * Provides random, weighted access to a collection of elements. + *

+ * Intended to be thread-safe. + * + * @param The generic type parameter of the elements. + */ +public class RandomCollection +{ + + private final NavigableMap _map = Collections.synchronizedNavigableMap(new TreeMap()); + private final Random _random; + + private double total = 0; + + public RandomCollection(Random random) + { + _random = random; + } + + public RandomCollection() + { + this(ThreadLocalRandom.current()); + } + + public void addAll(Map values) + { + values.forEach(this::add); + } + + public void add(E result, double weight) + { + if (weight <= 0) + { + return; + } + + total += weight; + _map.put(total, result); + } + + public E next() + { + double value = _random.nextDouble() * total; + return _map.ceilingEntry(value).getValue(); + } + + public Collection values() + { + return _map.values(); + } +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/UtilGoogleSheet.java b/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/UtilGoogleSheet.java new file mode 100644 index 000000000..6dee08b44 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/common/util/UtilGoogleSheet.java @@ -0,0 +1,75 @@ +package mineplex.quest.common.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +/** + * Provides utility methods for deserializing google sheets json files. + */ +public class UtilGoogleSheet +{ + private static final File DATA_STORE_DIR = new File( + ".." + File.separatorChar + ".." + File.separatorChar + "update" + File.separatorChar + + "files"); + + public static Map>> getSheetData(String name) + { + return getSheetData(new File(DATA_STORE_DIR + File.separator + name + ".json")); + } + + public static Map>> getSheetData(File file) + { + if (!file.exists()) + { + return null; + } + + Map>> valuesMap = new HashMap<>(); + + try + { + JsonParser parser = new JsonParser(); + JsonElement data = parser.parse(new FileReader(file)); + JsonArray parent = data.getAsJsonObject().getAsJsonArray("data"); + + for (int i = 0; i < parent.size(); i++) + { + JsonObject sheet = parent.get(i).getAsJsonObject(); + String name = sheet.get("name").getAsString(); + JsonArray values = sheet.getAsJsonArray("values"); + List> valuesList = new ArrayList<>(values.size()); + + for (int j = 0; j < values.size(); j++) + { + List list = new ArrayList<>(); + Iterator iterator = values.get(j).getAsJsonArray().iterator(); + + while (iterator.hasNext()) + { + String value = iterator.next().getAsString(); + list.add(value); + } + + valuesList.add(list); + } + + valuesMap.put(name, valuesList); + } + } + catch (FileNotFoundException e) + {} + + return valuesMap; + } +} \ No newline at end of file diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestDaemon.java b/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestDaemon.java new file mode 100644 index 000000000..15dbb2d55 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestDaemon.java @@ -0,0 +1,180 @@ +package mineplex.quest.daemon; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.fusesource.jansi.AnsiConsole; + +import com.google.common.base.Throwables; + +import mineplex.serverdata.redis.messaging.PubSubJedisClient; +import mineplex.serverdata.redis.messaging.PubSubRouter; +import mineplex.serverdata.servers.ServerManager; + +import jline.console.ConsoleReader; + +/** + * Entry point for a {@link QuestManager} service. + */ +public class QuestDaemon +{ + + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM:dd:yyyy HH:mm:ss"); + + private static final Logger _logger = Logger.getLogger("QuestManager"); + static + { + FileHandler fileHandler; + try + { + fileHandler = new FileHandler("monitor.log", true); + fileHandler.setFormatter(new Formatter() + { + @Override + public String format(LogRecord record) + { + return record.getMessage() + "\n"; + } + }); + _logger.addHandler(fileHandler); + _logger.setUseParentHandlers(false); + } + catch (SecurityException | IOException e) + { + log("COuld not initialize log file!"); + log(e); + } + } + + private volatile boolean _alive = true; + + private QuestManager _questManager; + + public static void main(String[] args) + { + try + { + new QuestDaemon().run(); + System.exit(0); + } + catch (Throwable t) + { + log("Error in startup/console thread."); + log(t); + System.exit(1); + } + } + + private void run() throws Exception + { + log("Starting QuestDaemon..."); + + _questManager = new QuestManager(new PubSubRouter(new PubSubJedisClient( + ServerManager.getMasterConnection(), ServerManager.getSlaveConnection()))); + _questManager.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> _questManager.onShutdown())); + + AnsiConsole.systemInstall(); + ConsoleReader consoleReader = new ConsoleReader(); + consoleReader.setExpandEvents(false); + + String command; + while (_alive && (command = consoleReader.readLine(">")) != null) + { + try + { + if (command.equals("help")) + { + log("QuestManager commands:"); + log("stop: Shuts down this QuestManager instance."); + log("clearactivequests: Clears active quests. New ones will be selected on this" + + " instance's next iteration."); + log("clearrecentrequests: Clear recently selected quests. This effectively allows " + + "any quest to be set to active, even ones selected within the past few days."); + log("getactivequests: Displays the currently active quests."); + } + else if (command.contains("stop")) + { + stopCommand(); + } + else if (command.contains("clearactivequests")) + { + clearQuestsCommand(); + } + else if (command.contains("clearrecentquests")) + { + clearRecentQuestsCommand(); + } + else if (command.contains("getactivequests")) + { + getActiveQuestsCommand(); + } + } + catch (Throwable t) + { + log("Exception encountered while executing command " + command + ": " + + t.getMessage()); + log(t); + } + } + } + + private void stopCommand() throws Exception + { + log("Shutting down QuestDaemon..."); + + _alive = false; + + System.exit(0); + } + + private void clearQuestsCommand() + { + _questManager.clearActiveQuests(); + + log("Cleared active quests. New ones will be selected on this instance's next iteration."); + } + + private void clearRecentQuestsCommand() + { + _questManager.clearRecentlyActiveQuests(); + + log("Cleared recently active quests. This means that any quest can be chosen to be active now, even ones selected within the past few days."); + } + + private void getActiveQuestsCommand() + { + _questManager.displayActiveQuests(); + } + + public static void log(String message) + { + log(message, false); + } + + public static void log(Throwable t) + { + log(Throwables.getStackTraceAsString(t)); + } + + public static void log(String message, boolean fileOnly) + { + _logger.info("[" + DATE_FORMAT.format(new Date()) + "] " + message); + + if (!fileOnly) + { + System.out.println("[" + DATE_FORMAT.format(new Date()) + "] " + message); + } + } + + public static String getLogPrefix(Object loggingClass) + { + return "[" + DATE_FORMAT.format(new Date()) + "] "; + } +} diff --git a/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestManager.java b/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestManager.java new file mode 100644 index 000000000..46686de98 --- /dev/null +++ b/Plugins/mineplex-questmanager/src/mineplex/quest/daemon/QuestManager.java @@ -0,0 +1,277 @@ +package mineplex.quest.daemon; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import mineplex.quest.common.Quest; +import mineplex.quest.common.QuestRarity; +import mineplex.quest.common.Quests; +import mineplex.quest.common.redis.PubSubChannels; +import mineplex.quest.common.redis.QuestRedisDataRepository; +import mineplex.quest.common.redis.QuestTypeSerializer; +import mineplex.quest.common.util.RandomCollection; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.redis.messaging.PubSubMessager; +import mineplex.serverdata.servers.ServerManager; + +/** + * A centralized service that handles setting {@link Quest} instances as active for servers to + * display to players. Uses redis to notify servers of active quests changes and to store recently + * selected quests. + *

+ * Uses {@link QuestRarity} to randomly select active quests based on relative weight. + */ +public class QuestManager extends Thread +{ + + private static final int RECENT_QUESTS_EXPIRE_SECONDS = (int) TimeUnit.DAYS.toSeconds(5); + private static final long SLEEP_MILLIS = TimeUnit.MINUTES.toMillis(1); + private static final int NUM_ACTIVE_QUESTS = 5; + + private static final ZoneId EST_TIMEZONE = ZoneId.of("America/New_York"); + private static final String LAST_UPDATE_FILE = "last-quest-update.dat"; + + // all quests, mapped from rarity weight to quest + private final RandomCollection _quests = new RandomCollection<>(); + + // currently active quests + private final Set _activeQuests = Collections.synchronizedSet(new HashSet<>()); + + // redis pubsub messager, used to publish active quests to servers + private final PubSubMessager _pubSub; + + // redis repository to track recently selected quests, to prevent selecting a quest too soon + // after it's been active + private final DataRepository _recentlySelectedQuestsRepo; + + // the current date, e.g. the last date active quests were updated + private volatile LocalDate _currentDate; + + // whether this instance is running or not + private volatile boolean _alive = true; + + public QuestManager(PubSubMessager pubSub) + { + _pubSub = pubSub; + + _recentlySelectedQuestsRepo = new QuestRedisDataRepository( + ServerManager.getMasterConnection(), ServerManager.getSlaveConnection(), + Region.currentRegion(), "recently-selected-quests"); + + _quests.addAll(Quests.QUESTS.stream().collect( + Collectors.toMap(q -> q, q -> q.getRarity().getWeight()))); + + loadLastActiveQuests(); + + if (_activeQuests.size() > 0) + { + QuestDaemon.log("Active quests loaded from file:"); + _activeQuests.forEach(quest -> QuestDaemon.log(quest.toString())); + } + + // listen for servers requesting active quests on startup + _pubSub.subscribe(PubSubChannels.QUEST_REQUEST_BASE, this::handleQuestRequest); + } + + private void handleQuestRequest(String channel, String message) + { + QuestDaemon.log("Quests requestesd by server: " + message); + // first make sure we have some active quests selected + if (_activeQuests.isEmpty()) + { + selectRandomQuests(); + } + + // send active quests to the server + String server = message; + publishActiveQuests(PubSubChannels.QUEST_REQUEST_BASE + server); + } + + /** + * Loads last set active quests & the date they were set to active from a flat file, if the file + * exists. + */ + private void loadLastActiveQuests() + { + File file = new File(LAST_UPDATE_FILE); + if (!file.exists()) + { + _currentDate = LocalDate.now(EST_TIMEZONE); + + return; + } + + try + { + List lines = Files.readAllLines(Paths.get(file.getAbsolutePath())); + _currentDate = LocalDate.parse(lines.get(0)); + + if (lines.size() > 1) + { + for (int i = 1; i < lines.size(); i++) + { + int uniqueId = Integer.parseInt(lines.get(i)); + Optional quest = Quests.fromId(uniqueId); + if (!quest.isPresent()) + { + QuestDaemon.log("Tried to load active quest that doesn't exist: " + uniqueId); + continue; + } + + _activeQuests.add(quest.get()); + } + } + } + catch (Exception e) + { + QuestDaemon.log( + "Exception encountered while loading last updated quests: " + e.getMessage()); + QuestDaemon.log(e); + + _currentDate = LocalDate.now(EST_TIMEZONE); + } + } + + @Override + public void run() + { + try + { + while (_alive) + { + // purge recently selected quests repo of expired entries + _recentlySelectedQuestsRepo.clean(); + + LocalDate now = LocalDate.now(EST_TIMEZONE); + // check if date has changed; if so we need to choose new quests + if (_currentDate.isBefore(now) || _activeQuests.isEmpty()) + { + QuestDaemon.log("Updating active quests..."); + _currentDate = now; + + // select new quests + selectRandomQuests(); + + // publish new quests + publishActiveQuests(PubSubChannels.QUEST_SUPPLIER_CHANNEL); + + QuestDaemon.log("Done updating active quests."); + } + + // take a small break, important so CPU isn't constantly running + Thread.sleep(SLEEP_MILLIS); + } + } + catch (InterruptedException e) + { + QuestDaemon.log("Exception encountered updating active quests repo: " + e.getMessage()); + QuestDaemon.log(e); + } + } + + private void publishActiveQuests(String channel) + { + QuestDaemon.log("publishing active quests to channel: " + channel); + QuestDaemon.log("Active quests: " + serialize(_activeQuests)); + _pubSub.publish(channel, + serialize(_activeQuests)); + } + + /** + * Called on shutdown of this service. Writes the date quests were last updated to a file, so + * this service will know whether to update them or not on the next startup. This is all that's + * needed to keep active quests in a sane state because they are stored in redis. + */ + public void onShutdown() + { + _alive = false; + + try + { + File file = new File(LAST_UPDATE_FILE); + if (!file.exists()) + { + file.createNewFile(); + } + + List lines = new ArrayList<>(); + + // add active quests date + lines.add(_currentDate.toString()); + + // add currently active quests + _activeQuests.stream().map(Quest::getDataId).forEach(lines::add); + + Files.write(Paths.get(file.getAbsolutePath()), lines); + } + catch (IOException e) + { + QuestDaemon.log("Exception encountered saving " + LAST_UPDATE_FILE + " file: " + + e.getMessage()); + QuestDaemon.log(e); + } + } + + protected void clearActiveQuests() + { + _activeQuests.clear(); + } + + protected void clearRecentlyActiveQuests() + { + _recentlySelectedQuestsRepo.getElements() + .forEach(_recentlySelectedQuestsRepo::removeElement); + } + + protected void displayActiveQuests() + { + QuestDaemon.log("Active quests:"); + _activeQuests.forEach(q -> QuestDaemon.log(q.toString())); + } + + private void selectRandomQuests() + { + if (!_activeQuests.isEmpty()) + { + _activeQuests.clear(); + } + + while (_activeQuests.size() < NUM_ACTIVE_QUESTS && _activeQuests.size() < _quests.values().size()) + { + Quest q = _quests.next(); + // select random weighted quest, ignore those recently selected + if (!q.shouldRotate() || _activeQuests.contains(q) + || _recentlySelectedQuestsRepo.elementExists(q.getDataId())) + { + // quest is already active or it's been active recently + continue; + } + + // add active quest + _activeQuests.add(q); + + QuestDaemon.log("Selected quest: " + q.getName()); + + // flag quest as recently selected + _recentlySelectedQuestsRepo.addElement(q, RECENT_QUESTS_EXPIRE_SECONDS); + } + } + + private String serialize(Set quests) + { + return QuestTypeSerializer.QUEST_GSON.toJson(quests, QuestTypeSerializer.QUEST_TYPE); + } +} diff --git a/Plugins/pom.xml b/Plugins/pom.xml index 46ff3c9e3..bbf652166 100644 --- a/Plugins/pom.xml +++ b/Plugins/pom.xml @@ -43,6 +43,7 @@ mavericks-review-hub mineplex-game-gemhunters mineplex-google-sheets + mineplex-questmanager