diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/TriConsumer.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/TriConsumer.java
new file mode 100644
index 000000000..eca685883
--- /dev/null
+++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/TriConsumer.java
@@ -0,0 +1,54 @@
+package mineplex.core.common;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts two input arguments and returns no
+ * result. This is the three-arity specialization of {@link Consumer}.
+ * Unlike most other functional interfaces, {@code TriConsumer} is expected
+ * to operate via side-effects.
+ *
+ *
This is a functional interface
+ * whose functional method is {@link #accept(Object, Object, Object)}.
+ *
+ * @param the type of the first argument to the operation
+ * @param the type of the second argument to the operation
+ * @param the type of the third argument to the operation
+ *
+ * @see Consumer
+ */
+@FunctionalInterface
+public interface TriConsumer
+{
+
+ /**
+ * Performs this operation on the given arguments.
+ *
+ * @param t the first input argument
+ * @param u the second input argument
+ * @param v the third input argument
+ */
+ void accept(T t, U u, V v);
+
+ /**
+ * Returns a composed {@code TriConsumer} that performs, in sequence, this
+ * operation followed by the {@code after} operation. If performing either
+ * operation throws an exception, it is relayed to the caller of the
+ * composed operation. If performing this operation throws an exception,
+ * the {@code after} operation will not be performed.
+ *
+ * @param after the operation to perform after this operation
+ * @return a composed {@code TriConsumer} that performs in sequence this
+ * operation followed by the {@code after} operation
+ * @throws NullPointerException if {@code after} is null
+ */
+ default TriConsumer andThen(TriConsumer super T, ? super U, ? super V> after)
+ {
+ Objects.requireNonNull(after);
+
+ return (f, s, t) -> {
+ accept(f, s, t);
+ after.accept(f, s, t);
+ };
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java
index 580b337f5..7af6ab2dd 100644
--- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java
+++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilEnt.java
@@ -1032,7 +1032,12 @@ public class UtilEnt
return null;
}
- return entity.getMetadata(key).get(0);
+ return entity.getMetadata(key).get(0).value();
+ }
+
+ public static void removeMetadata(Entity entity, String key)
+ {
+ entity.removeMetadata(key, UtilServer.getPlugin());
}
public static void SetItemInHand(LivingEntity entity, ItemStack item)
diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilItem.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilItem.java
index 3f933517b..47fd7594c 100644
--- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilItem.java
+++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilItem.java
@@ -1158,6 +1158,16 @@ public class UtilItem
return i;
}
+ public static boolean isUnbreakable(ItemStack i)
+ {
+ if (i == null)
+ {
+ return false;
+ }
+
+ return i.getItemMeta().spigot().isUnbreakable();
+ }
+
/**
*
diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilMath.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilMath.java
index bd9e1600c..5e37e0ac5 100644
--- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilMath.java
+++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilMath.java
@@ -54,6 +54,23 @@ public class UtilMath
return a.subtract(b).length();
}
+ public static double offset2dSquared(Entity a, Entity b)
+ {
+ return offset2dSquared(a.getLocation().toVector(), b.getLocation().toVector());
+ }
+
+ public static double offset2dSquared(Location a, Location b)
+ {
+ return offset2dSquared(a.toVector(), b.toVector());
+ }
+
+ public static double offset2dSquared(Vector a, Vector b)
+ {
+ a.setY(0);
+ b.setY(0);
+ return a.subtract(b).lengthSquared();
+ }
+
public static double offset(Entity a, Entity b)
{
return offset(a.getLocation().toVector(), b.getLocation().toVector());
@@ -283,4 +300,36 @@ public class UtilMath
{
return n - ((int) ((int) n));
}
+
+ public static int getMax(int... ints)
+ {
+ if (ints.length < 1)
+ {
+ return -1;
+ }
+ int max = ints[0];
+
+ for (int i = 1; i < ints.length; i++)
+ {
+ max = Math.max(max, ints[i]);
+ }
+
+ return max;
+ }
+
+ public static int getMin(int... ints)
+ {
+ if (ints.length < 1)
+ {
+ return -1;
+ }
+ int min = ints[0];
+
+ for (int i = 1; i < ints.length; i++)
+ {
+ min = Math.min(min, ints[i]);
+ }
+
+ return min;
+ }
}
diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java
index 6294181ab..0bb9502f6 100644
--- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java
+++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilPlayer.java
@@ -595,8 +595,13 @@ public class UtilPlayer
return nearbyMap;
}
-
+
public static Player getClosest(Location loc, Collection ignore)
+ {
+ return getClosest(loc, -1, ignore);
+ }
+
+ public static Player getClosest(Location loc, double maxDist, Collection ignore)
{
Player best = null;
double bestDist = 0;
@@ -613,6 +618,11 @@ public class UtilPlayer
continue;
double dist = UtilMath.offset(cur.getLocation(), loc);
+
+ if (maxDist > 0 && dist > maxDist)
+ {
+ continue;
+ }
if (best == null || dist < bestDist)
{
@@ -623,8 +633,13 @@ public class UtilPlayer
return best;
}
-
+
public static Player getClosest(Location loc, Entity... ignore)
+ {
+ return getClosest(loc, -1, ignore);
+ }
+
+ public static Player getClosest(Location loc, double maxDist, Entity... ignore)
{
Player best = null;
double bestDist = 0;
@@ -654,7 +669,12 @@ public class UtilPlayer
continue;
}
- double dist = UtilMath.offsetSquared(cur.getLocation(), loc);
+ double dist = UtilMath.offset(cur.getLocation(), loc);
+
+ if (maxDist > 0 && dist > maxDist)
+ {
+ continue;
+ }
if (best == null || dist < bestDist)
{
diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java
index 0c096b119..30d4ae905 100644
--- a/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java
+++ b/Plugins/Mineplex.Core/src/mineplex/core/account/CoreClientManager.java
@@ -176,7 +176,7 @@ public class CoreClientManager extends MiniPlugin
}
/**
- * Get the databse account id for a player. Requires the player is online
+ * Get the database account id for a player. Requires the player is online
*
* @param player
* @return
diff --git a/Plugins/Mineplex.Core/src/mineplex/core/account/command/TestRank.java b/Plugins/Mineplex.Core/src/mineplex/core/account/command/TestRank.java
index e4ab7147e..e4ed2e7b8 100644
--- a/Plugins/Mineplex.Core/src/mineplex/core/account/command/TestRank.java
+++ b/Plugins/Mineplex.Core/src/mineplex/core/account/command/TestRank.java
@@ -64,7 +64,7 @@ public class TestRank extends CommandBase
UtilPlayer.message(caller, F.main(Plugin.getName(), ChatColor.RED + "" + ChatColor.BOLD + "Invalid rank!"));
return;
}
- if (Plugin.Get(caller).GetRank(true) == Rank.SNR_MODERATOR)
+ if (!Plugin.Get(caller).GetRank(true).has(Rank.JNR_DEV))
{
if (tempRank.has(Rank.TWITCH))
{
diff --git a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemStackFactory.java b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemStackFactory.java
index 8ca03762a..6cff9e3ba 100644
--- a/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemStackFactory.java
+++ b/Plugins/Mineplex.Core/src/mineplex/core/itemstack/ItemStackFactory.java
@@ -1000,10 +1000,10 @@ public class ItemStackFactory extends MiniPlugin
ItemMeta meta = stack.getItemMeta();
if (meta == null)
- return 0;
+ return empty;
if (meta.getLore() == null)
- return 0;
+ return empty;
for (String cur : meta.getLore())
if (cur.contains(var))
@@ -1021,7 +1021,7 @@ public class ItemStackFactory extends MiniPlugin
}
- return 0;
+ return empty;
}
public void SetLoreVar(ItemStack stack, String var, String value)
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java
index 8bddf656b..784e5c230 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java
@@ -1,7 +1,9 @@
package mineplex.game.clans;
-import mineplex.core.aprilfools.AprilFoolsManager;
-import net.minecraft.server.v1_8_R3.MinecraftServer;
+import static mineplex.core.Managers.require;
+
+import java.io.File;
+import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -11,7 +13,6 @@ import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.plugin.java.JavaPlugin;
import org.spigotmc.SpigotConfig;
-import mineplex.core.common.Constants;
import mineplex.core.CustomTagFix;
import mineplex.core.FoodDupeFix;
import mineplex.core.TimingsFix;
@@ -20,12 +21,14 @@ import mineplex.core.achievement.AchievementManager;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.guardians.AntiHackGuardian;
import mineplex.core.antihack.guardians.GuardianManager;
+import mineplex.core.aprilfools.AprilFoolsManager;
import mineplex.core.blockrestore.BlockRestore;
import mineplex.core.chat.Chat;
import mineplex.core.chatsnap.SnapshotManager;
import mineplex.core.chatsnap.SnapshotPlugin;
import mineplex.core.chatsnap.SnapshotRepository;
import mineplex.core.command.CommandCenter;
+import mineplex.core.common.Constants;
import mineplex.core.common.MinecraftVersion;
import mineplex.core.common.Pair;
import mineplex.core.common.events.ServerShutdownEvent;
@@ -74,12 +77,13 @@ import mineplex.game.clans.shop.mining.MiningShop;
import mineplex.game.clans.shop.pvp.PvpShop;
import mineplex.game.clans.spawn.travel.TravelShop;
import mineplex.game.clans.world.WorldManager;
-
-import static mineplex.core.Managers.require;
+import net.minecraft.server.v1_8_R3.MinecraftServer;
public class Clans extends JavaPlugin
{
- public static final String MAP = "Season 2";
+ public static final String MAP = "Season 3";
+
+ public static boolean HARDCORE = false;
// Modules
private CoreClientManager _clientManager;
@@ -89,6 +93,14 @@ public class Clans extends JavaPlugin
@Override
public void onEnable()
{
+ try
+ {
+ HARDCORE = new File(new File(".").getCanonicalPath() + File.separator + "Hardcore.dat").exists();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
Bukkit.setSpawnRadius(0);
// Configs
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java
index 1027a2253..78a0fd82c 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Farming.java
@@ -1,33 +1,17 @@
package mineplex.game.clans;
-import com.google.common.collect.Sets;
-import mineplex.core.MiniPlugin;
-import mineplex.core.common.util.UtilItem;
-import mineplex.core.itemstack.ItemStackFactory;
-import mineplex.core.common.util.F;
-import mineplex.core.common.util.UtilPlayer;
-
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
-import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.plugin.java.JavaPlugin;
-import java.util.Set;
+import mineplex.core.MiniPlugin;
+import mineplex.core.common.util.UtilItem;
+import mineplex.core.itemstack.ItemStackFactory;
public class Farming extends MiniPlugin
{
- private static final Set PLANTABLE = Sets.newHashSet(
- Material.WHEAT,
- Material.SUGAR_CANE_BLOCK,
- Material.PUMPKIN_STEM,
- Material.MELON_STEM,
- Material.COCOA,
- Material.CARROT,
- Material.POTATO
- );
-
public Farming(JavaPlugin plugin)
{
super("Farming", plugin);
@@ -50,27 +34,4 @@ public class Farming extends MiniPlugin
if (Math.random() > 0.999)
event.getBlock().getWorld().dropItemNaturally(dropLocation, ItemStackFactory.Instance.CreateStack(Material.GOLDEN_APPLE));
}
-
- @EventHandler (ignoreCancelled = true)
- public void BlockPlace(BlockPlaceEvent event)
- {
- if (!PLANTABLE.contains(event.getBlock().getType()))
- return;
-
- double blockY = event.getBlock().getLocation().getY();
- double seaLevel = event.getBlock().getWorld().getSeaLevel();
-
- if (blockY < seaLevel - 12)
- {
- UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot plant " +
- F.item(ItemStackFactory.Instance.GetName(event.getPlayer().getItemInHand(), true)) + " this deep underground."));
- event.setCancelled(true);
- }
- else if (blockY > seaLevel + 24)
- {
- UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot plant " +
- F.item(ItemStackFactory.Instance.GetName(event.getPlayer().getItemInHand(), true)) + " at this altitude."));
- event.setCancelled(true);
- }
- }
-}
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClanInfo.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClanInfo.java
index a07074f98..2d4d42389 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClanInfo.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClanInfo.java
@@ -11,7 +11,6 @@ import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.Sound;
-import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import mineplex.core.common.util.C;
@@ -208,11 +207,18 @@ public class ClanInfo
}
public int getAlliesMax()
+ {
+ return getAlliesMaxWithMemberCountOf(_memberMap.size());
+ }
+
+ public int getAlliesMaxWithMemberCountOf(int memberCount)
{
if (ssAdmin())
+ {
return 1000;
-
- return Math.max(2, 9 - _memberMap.size());
+ }
+
+ return Math.max(2, 6 - memberCount);
}
public BedStatus getBedStatus()
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java
index 3b8c45896..fcc116670 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansAdmin.java
@@ -372,15 +372,11 @@ public class ClansAdmin
}
else
{
- Clans.getClanDataAccess().war(clan, clanAgainst, value, new Callback()
+ Clans.getClanDataAccess().war(clan, clanAgainst, value, data ->
{
- @Override
- public void run(ClanWarData data)
- {
- UtilPlayer.message(caller, F.main("Clans Admin", "Updated war points against " + F.elem(data.getClanB())));
- Clans.messageClan(clan, F.main("Clans", "Your war points with " + F.elem(clanAgainst.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
- Clans.messageClan(clanAgainst, F.main("Clans", "Your war points with " + F.elem(clan.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
- }
+ UtilPlayer.message(caller, F.main("Clans Admin", "Updated war points against " + F.elem(data.getClanB())));
+ Clans.messageClan(clan, F.main("Clans", "Your war points with " + F.elem(clanAgainst.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
+ Clans.messageClan(clanAgainst, F.main("Clans", "Your war points with " + F.elem(clan.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
});
}
}
@@ -401,15 +397,11 @@ public class ClansAdmin
}
else
{
- Clans.getClanDataAccess().war(clan, clanAgainst, value, new Callback()
+ Clans.getClanDataAccess().war(clan, clanAgainst, value, data ->
{
- @Override
- public void run(ClanWarData data)
- {
- UtilPlayer.message(caller, F.main("Clans Admin", "Updated war points against " + F.elem(data.getClanB())));
- Clans.messageClan(clan, F.main("Clans", "Your war points with " + F.elem(clanAgainst.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
- Clans.messageClan(clanAgainst, F.main("Clans", "Your war points with " + F.elem(clan.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
- }
+ UtilPlayer.message(caller, F.main("Clans Admin", "Updated war points against " + F.elem(data.getClanB())));
+ Clans.messageClan(clan, F.main("Clans", "Your war points with " + F.elem(clanAgainst.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
+ Clans.messageClan(clanAgainst, F.main("Clans", "Your war points with " + F.elem(clan.getName()) + " have been edited by " + F.elem(caller.getName()) + "!"));
});
}
}
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansBlocks.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansBlocks.java
index 6a38d402c..fe4755ca0 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansBlocks.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansBlocks.java
@@ -78,6 +78,8 @@ public class ClansBlocks
denyUsePlace.add(390); //Pot
denyUsePlace.add(404); //Comparator
denyUsePlace.add(407); //TNT Cart
+ denyUsePlace.add(287); //String
+ denyUsePlace.add(397); //Skulls
}
if (id == 65)
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansDisplay.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansDisplay.java
index 804690b92..0c5629d2d 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansDisplay.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansDisplay.java
@@ -9,6 +9,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.plugin.java.JavaPlugin;
+import mineplex.core.Managers;
import mineplex.core.MiniPlugin;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
@@ -20,6 +21,8 @@ import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.game.clans.clans.ClansUtility.ClanRelation;
import mineplex.game.clans.clans.event.PlayerEnterTerritoryEvent;
+import mineplex.game.clans.clans.nether.NetherManager;
+import mineplex.game.clans.clans.worldevent.WorldEventManager;
import mineplex.game.clans.core.repository.ClanTerritory;
public class ClansDisplay extends MiniPlugin
@@ -56,7 +59,7 @@ public class ClansDisplay extends MiniPlugin
client.setTerritory(UtilWorld.chunkToStr(player.getLocation().getChunk()));
// AutoClaim
- if (client.isAutoClaim()) _clansManager.getClanAdmin().claim(player);
+ if (client.isAutoClaim() && !(Managers.get(NetherManager.class).isInNether(player) || Managers.get(WorldEventManager.class).getRaidManager().isInRaid(player.getLocation()))) _clansManager.getClanAdmin().claim(player);
// Map
String owner = "Wilderness";
@@ -65,7 +68,7 @@ public class ClansDisplay extends MiniPlugin
boolean safe = _clansManager.getClanUtility().isSafe(player);
- PlayerEnterTerritoryEvent event = new PlayerEnterTerritoryEvent(player, client.getOwner(), owner, (owner.equals("Wilderness") && !_clansManager.getNetherManager().isInNether(player)) ? false : _clansManager.getClanUtility().getClaim(player.getLocation()).isSafe(player.getLocation()), true);
+ PlayerEnterTerritoryEvent event = new PlayerEnterTerritoryEvent(player, client.getOwner(), owner, safe, true);
UtilServer.getServer().getPluginManager().callEvent(event);
@@ -127,6 +130,11 @@ public class ClansDisplay extends MiniPlugin
}
}
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ ownerString = C.cDRed + "Raid World";
+ }
+
// if (_clansManager.getNetherManager().isInNether(player))
// {
// _clansManager.message(player, "You are not allowed to claim territory in " + F.clansNether("The Nether") + ".");
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java
index 989eb95b7..b5c293a04 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansManager.java
@@ -31,6 +31,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
@@ -85,11 +86,13 @@ import mineplex.core.task.TaskManager;
import mineplex.core.teleport.Teleport;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClanTips.TipType;
import mineplex.game.clans.clans.ClansUtility.ClanRelation;
import mineplex.game.clans.clans.amplifiers.AmplifierManager;
import mineplex.game.clans.clans.ban.ClansBanManager;
import mineplex.game.clans.clans.banners.BannerManager;
+import mineplex.game.clans.clans.boxes.BoxManager;
import mineplex.game.clans.clans.commands.ClanManagementCommand;
import mineplex.game.clans.clans.commands.ClansAllyChatCommand;
import mineplex.game.clans.clans.commands.ClansChatCommand;
@@ -104,6 +107,7 @@ import mineplex.game.clans.clans.gui.ClanShop;
import mineplex.game.clans.clans.invsee.InvseeManager;
import mineplex.game.clans.clans.loot.LootManager;
import mineplex.game.clans.clans.map.ItemMapManager;
+import mineplex.game.clans.clans.mounts.MountManager;
import mineplex.game.clans.clans.nameblacklist.ClansBlacklist;
import mineplex.game.clans.clans.nether.NetherManager;
import mineplex.game.clans.clans.observer.ObserverManager;
@@ -433,10 +437,10 @@ public class ClansManager extends MiniClientPluginimplements IRelati
new Location(Spawn.getSpawnWorld(), -25, 200, 390),
// East Spawn
- new Location(Spawn.getSpawnWorld(), 34, 200, -393),
- new Location(Spawn.getSpawnWorld(), 8, 200, -365),
- new Location(Spawn.getSpawnWorld(), -25, 200, -393),
- new Location(Spawn.getSpawnWorld(), 8, 200, -424)
+ new Location(Spawn.getSpawnWorld(), 34, 206, -393),
+ new Location(Spawn.getSpawnWorld(), 8, 206, -365),
+ new Location(Spawn.getSpawnWorld(), -25, 206, -393),
+ new Location(Spawn.getSpawnWorld(), 8, 206, -424)
);
List welcomeHolograms = Arrays.asList(
@@ -444,10 +448,10 @@ public class ClansManager extends MiniClientPluginimplements IRelati
new Location(Spawn.getSpawnWorld(), 8, 200, 399),
new Location(Spawn.getSpawnWorld(), 0, 200, 390),
new Location(Spawn.getSpawnWorld(), 8, 200, 381),
- new Location(Spawn.getSpawnWorld(), 8, 200, -384),
- new Location(Spawn.getSpawnWorld(), 0, 200, -393),
- new Location(Spawn.getSpawnWorld(), 8, 200, -402),
- new Location(Spawn.getSpawnWorld(), 17, 200, -393)
+ new Location(Spawn.getSpawnWorld(), 8, 206, -384),
+ new Location(Spawn.getSpawnWorld(), 0, 206, -393),
+ new Location(Spawn.getSpawnWorld(), 8, 206, -402),
+ new Location(Spawn.getSpawnWorld(), 17, 206, -393)
);
for (Location location : jumpOffHolograms)
@@ -472,6 +476,10 @@ public class ClansManager extends MiniClientPluginimplements IRelati
_netherManager = new NetherManager(this);
_amplifierManager = new AmplifierManager(plugin);
+ new MountManager(plugin, clientManager, donationManager);
+
+ new BoxManager(plugin);
+
_restartManager = new RestartManager(plugin);
}
@@ -650,6 +658,19 @@ public class ClansManager extends MiniClientPluginimplements IRelati
public long lastPower = System.currentTimeMillis();
+ @EventHandler
+ public void displayHardcoreMode(ServerListPingEvent event)
+ {
+ if (Clans.HARDCORE)
+ {
+ event.setMotd("Hardcore");
+ }
+ else
+ {
+ event.setMotd("Casual");
+ }
+ }
+
@EventHandler
public void savePlayerActiveBuild(PlayerQuitEvent event)
{
@@ -912,7 +933,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati
recipients.clear();
}
- @EventHandler
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void disableObsidian(BlockBreakEvent event)
{
if(event.getBlock().getType().equals(Material.OBSIDIAN))
@@ -1220,6 +1241,7 @@ public class ClansManager extends MiniClientPluginimplements IRelati
_safeLog.onDisable();
_restartManager.onDisable();
_observerManager.onDisable();
+ Managers.get(MountManager.class).onDisable();
}
@EventHandler(priority = EventPriority.HIGHEST)
@@ -1387,29 +1409,6 @@ public class ClansManager extends MiniClientPluginimplements IRelati
}
}
- @EventHandler
- public void damageHorse(EntityDamageEvent event)
- {
- if (event.getEntity() instanceof Horse)
- {
- if (event.getEntity().getPassenger() != null && event.getEntity().getPassenger() instanceof Player)
- {
- event.getEntity().getPassenger().eject();
- Recharge.Instance.use((Player) event.getEntity().getPassenger(), "Ride Horse", 2 * 20L, false, false);
- }
- event.getEntity().eject();
-
- }
- else if(event.getEntity() instanceof Player)
- {
- if(event.getEntity().getVehicle() != null && event.getEntity().getVehicle() instanceof Horse)
- {
- Recharge.Instance.use((Player) event.getEntity(), "Ride Horse", 2 * 20L, false, false);
- event.getEntity().getVehicle().eject();
- }
- }
- }
-
public Pair leftRecently(UUID uniqueId, long time)
{
if (_clanMemberLeftMap.containsKey(uniqueId) && (System.currentTimeMillis() - _clanMemberLeftMap.get(uniqueId).getRight()) <= time)
@@ -1465,4 +1464,4 @@ public class ClansManager extends MiniClientPluginimplements IRelati
{
return _incognitoManager;
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java
index b1c63970f..a2ecef65e 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ClansUtility.java
@@ -1221,6 +1221,12 @@ public class ClansUtility
UtilPlayer.message(caller, F.main("Clans", "You cannot invite yourself."));
return;
}
+
+ if (clan.getAllies() > clan.getAlliesMaxWithMemberCountOf(clan.getSize() + 1))
+ {
+ UtilPlayer.message(caller, F.main("Clans", "You cannot invite more members until you remove some allies."));
+ return;
+ }
// Inform
clan.inform(F.name(caller.getName()) + " invited " + F.name(target.getName()) + " to join your Clan.", caller.getName());
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ban/ClansBanManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ban/ClansBanManager.java
index 8b3d18877..ab8e38228 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ban/ClansBanManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/ban/ClansBanManager.java
@@ -266,7 +266,7 @@ public class ClansBanManager extends MiniPlugin
player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 999999, -10));
for (Player alert : UtilServer.GetPlayers())
{
- if (_clientManager.Get(staff).GetRank().has(null, Rank.ADMIN, new Rank[] {Rank.CMOD, Rank.CMA}, false))
+ if (_clientManager.Get(alert).GetRank().has(null, Rank.ADMIN, new Rank[] {Rank.CMOD, Rank.CMA}, false))
{
UtilPlayer.message(alert, F.main(getName(), F.elem(player.getName()) + " has been frozen by " + F.elem(staff.getName()) + "!"));
}
@@ -287,7 +287,7 @@ public class ClansBanManager extends MiniPlugin
player.removePotionEffect(PotionEffectType.JUMP);
for (Player alert : UtilServer.GetPlayers())
{
- if (_clientManager.Get(staff).GetRank().has(null, Rank.ADMIN, new Rank[] {Rank.CMOD, Rank.CMA}, false))
+ if (_clientManager.Get(alert).GetRank().has(null, Rank.ADMIN, new Rank[] {Rank.CMOD, Rank.CMA}, false))
{
UtilPlayer.message(alert, F.main(getName(), F.elem(player.getName()) + " has been unfrozen by " + F.elem(staff.getName()) + "!"));
continue;
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/banners/BannerManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/banners/BannerManager.java
index 307e1590d..6b5503b3c 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/banners/BannerManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/banners/BannerManager.java
@@ -10,6 +10,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPlaceEvent;
@@ -170,7 +171,7 @@ public class BannerManager extends MiniPlugin
}
}
- @EventHandler
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBreak(BlockBreakEvent event)
{
if (event.getBlock().getType() == Material.STANDING_BANNER || event.getBlock().getType() == Material.WALL_BANNER)
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxManager.java
new file mode 100644
index 000000000..c0019ad74
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxManager.java
@@ -0,0 +1,222 @@
+package mineplex.game.clans.clans.boxes;
+
+import java.util.function.Consumer;
+
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.inventory.CraftItemEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.inventory.PrepareItemCraftEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import mineplex.core.Managers;
+import mineplex.core.MiniPlugin;
+import mineplex.core.command.CommandBase;
+import mineplex.core.common.Rank;
+import mineplex.core.common.util.C;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.game.clans.clans.boxes.extra.BuilderBoxInventory;
+import mineplex.game.clans.clans.boxes.extra.DyeBoxSpinner;
+
+public class BoxManager extends MiniPlugin
+{
+ private BuilderBoxInventory _builderBox;
+
+ public BoxManager(JavaPlugin plugin)
+ {
+ super("Box Manager", plugin);
+
+ final BoxShop shop = new BoxShop(this);
+
+ _builderBox = new BuilderBoxInventory();
+
+ addCommand(new CommandBase(this, Rank.ALL, "boxes", "box")
+ {
+ @Override
+ public void Execute(Player caller, String[] args)
+ {
+ shop.attemptShopOpen(caller);
+ }
+ });
+ }
+
+ @EventHandler(priority=EventPriority.HIGHEST)
+ public void onCraftWithDye(PrepareItemCraftEvent event)
+ {
+ if (event.getInventory().getResult() == null)
+ {
+ return;
+ }
+ if (event.getInventory().getResult().getType() == Material.LAPIS_BLOCK)
+ {
+ for (ItemStack item : event.getInventory().getMatrix())
+ {
+ if (item == null)
+ {
+ continue;
+ }
+ if (item.hasItemMeta() && item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().equals(C.cGold + "Dye"))
+ {
+ event.getInventory().setResult(null);
+ return;
+ }
+ }
+ return;
+ }
+ if (event.getInventory().getResult().getType() == Material.INK_SACK)
+ {
+ event.getInventory().setResult(null);
+ return;
+ }
+ for (ItemStack item : event.getInventory().getMatrix())
+ {
+ if (item == null)
+ {
+ continue;
+ }
+ if (item.getType() != Material.INK_SACK)
+ {
+ continue;
+ }
+ if (!item.hasItemMeta() || !item.getItemMeta().hasDisplayName() || !item.getItemMeta().getDisplayName().equals(C.cGold + "Dye"))
+ {
+ event.getInventory().setResult(null);
+ }
+ }
+ }
+
+ @EventHandler(priority=EventPriority.HIGHEST)
+ public void onCraftWithDye(CraftItemEvent event)
+ {
+ if (event.getInventory().getResult() == null)
+ {
+ return;
+ }
+ if (event.getInventory().getResult().getType() == Material.LAPIS_BLOCK)
+ {
+ for (ItemStack item : event.getInventory().getMatrix())
+ {
+ if (item == null)
+ {
+ continue;
+ }
+ if (item.hasItemMeta() && item.getItemMeta().hasDisplayName() && item.getItemMeta().getDisplayName().equals(C.cGold + "Dye"))
+ {
+ event.setCancelled(true);
+ return;
+ }
+ }
+ return;
+ }
+ if (event.getInventory().getResult().getType() == Material.INK_SACK)
+ {
+ event.setCancelled(true);
+ return;
+ }
+ for (ItemStack item : event.getInventory().getMatrix())
+ {
+ if (item == null)
+ {
+ continue;
+ }
+ if (item.getType() != Material.INK_SACK)
+ {
+ continue;
+ }
+ if (!item.hasItemMeta() || !item.getItemMeta().hasDisplayName() || !item.getItemMeta().getDisplayName().equals(C.cGold + "Dye"))
+ {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler(priority=EventPriority.HIGHEST)
+ public void onPlaceDyeInAnvil(InventoryClickEvent event)
+ {
+ if (!(event.getWhoClicked() instanceof Player))
+ {
+ return;
+ }
+ if (!event.getInventory().getType().equals(InventoryType.ANVIL))
+ {
+ return;
+ }
+ if (!(event.getCursor() != null && event.getCursor().hasItemMeta() && event.getCursor().getItemMeta().hasDisplayName() && event.getCursor().getItemMeta().getDisplayName().equals(C.cGold + "Dye")) && !(event.getCurrentItem() != null && event.getCurrentItem().hasItemMeta() && event.getCurrentItem().getItemMeta().hasDisplayName() && event.getCurrentItem().getItemMeta().getDisplayName().equals(C.cGold + "Dye")))
+ {
+ return;
+ }
+ event.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent event)
+ {
+ if (event.getItem() == null || !event.getItem().hasItemMeta() || !event.getItem().getItemMeta().hasDisplayName())
+ {
+ return;
+ }
+ if (event.getItem().getItemMeta().getDisplayName().equals(C.cGold + "Dye"))
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ public static enum BoxType
+ {
+ BUILDER_BOX("Clans Builder Box", C.cGold + "Builder's Box", Material.GLOWSTONE, Managers.get(BoxManager.class)._builderBox::open),
+ @SuppressWarnings("deprecation")
+ DYE_BOX("Clans Dye Box", C.cGreen + "Dye Box", Material.INK_SACK, DyeColor.RED.getDyeData(), DyeBoxSpinner::createSpinner),
+ ;
+
+ private String _itemName, _displayName;
+ private ItemBuilder _displayBuilder;
+ private Consumer _itemGenerator;
+
+ private BoxType(String itemName, String displayName, Material displayMaterial, Consumer itemGenerator)
+ {
+ _itemName = itemName;
+ _displayName = displayName;
+ _displayBuilder = new ItemBuilder(displayMaterial).setTitle(displayName).addLore(C.cRed);
+ _itemGenerator = itemGenerator;
+ }
+
+ private BoxType(String itemName, String displayName, Material displayMaterial, short data, Consumer itemGenerator)
+ {
+ _itemName = itemName;
+ _displayName = displayName;
+ _displayBuilder = new ItemBuilder(displayMaterial).setData(data).setTitle(displayName).addLore(C.cRed);
+ _itemGenerator = itemGenerator;
+ }
+
+ public String getItemName()
+ {
+ return _itemName;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+
+ public ItemStack getDisplayItem(int owned)
+ {
+ ItemBuilder newBuilder = new ItemBuilder(_displayBuilder.build());
+ if (owned > 0)
+ {
+ newBuilder.setGlow(true);
+ }
+ return newBuilder.addLore(C.cGreenB + "Owned: " + C.cWhite + owned).build();
+ }
+
+ public void onUse(Player player)
+ {
+ _itemGenerator.accept(player);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxOverviewPage.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxOverviewPage.java
new file mode 100644
index 000000000..bd17da0de
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxOverviewPage.java
@@ -0,0 +1,49 @@
+package mineplex.game.clans.clans.boxes;
+
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+
+import mineplex.core.recharge.Recharge;
+import mineplex.core.shop.item.IButton;
+import mineplex.core.shop.page.ShopPageBase;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.boxes.BoxManager.BoxType;
+
+public class BoxOverviewPage extends ShopPageBase
+{
+ public BoxOverviewPage(BoxManager plugin, BoxShop shop, String name, Player player)
+ {
+ super(plugin, shop, ClansManager.getInstance().getClientManager(), ClansManager.getInstance().getDonationManager(), name, player, 9);
+
+ buildPage();
+ }
+
+ @Override
+ protected void buildPage()
+ {
+ int[] slots = {3, 5};
+ for (int i = 0; i < BoxType.values().length && i < slots.length; i++)
+ {
+ BoxType type = BoxType.values()[i];
+ int slot = slots[i];
+ final int owns = ClansManager.getInstance().getInventoryManager().Get(getPlayer()).getItemCount(type.getItemName());
+ IButton button = (player, clickType) ->
+ {
+ if (owns < 1)
+ {
+ playDenySound(player);
+ }
+ else
+ {
+ player.closeInventory();
+ player.playSound(player.getLocation(), Sound.CHEST_OPEN, 1f, 1f);
+ if (Recharge.Instance.use(player, "Clans Box Click", 1000, false, false))
+ {
+ type.onUse(player);
+ }
+ }
+ };
+ addButton(slot, type.getDisplayItem(owns), button);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxShop.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxShop.java
new file mode 100644
index 000000000..bc7e8a852
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/BoxShop.java
@@ -0,0 +1,21 @@
+package mineplex.game.clans.clans.boxes;
+
+import org.bukkit.entity.Player;
+
+import mineplex.core.shop.ShopBase;
+import mineplex.core.shop.page.ShopPageBase;
+import mineplex.game.clans.clans.ClansManager;
+
+public class BoxShop extends ShopBase
+{
+ public BoxShop(BoxManager plugin)
+ {
+ super(plugin, ClansManager.getInstance().getClientManager(), ClansManager.getInstance().getDonationManager(), "Your Boxes");
+ }
+
+ @Override
+ protected ShopPageBase> buildPagesFor(Player player)
+ {
+ return new BoxOverviewPage(getPlugin(), this, "Your Boxes", player);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/BuilderBoxInventory.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/BuilderBoxInventory.java
new file mode 100644
index 000000000..e45db862a
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/BuilderBoxInventory.java
@@ -0,0 +1,171 @@
+package mineplex.game.clans.clans.boxes.extra;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.bukkit.Bukkit;
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryView;
+import org.bukkit.inventory.ItemStack;
+
+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.common.util.UtilServer;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.boxes.BoxManager.BoxType;
+
+public class BuilderBoxInventory implements Listener
+{
+ private Map, ItemStack> _replace = new HashMap<>();
+
+ public BuilderBoxInventory()
+ {
+ _replace.put(Pair.create(Material.STONE, (byte)0), new ItemStack(Material.STAINED_CLAY));
+ _replace.put(Pair.create(Material.GLASS, (byte)0), new ItemStack(Material.STAINED_GLASS));
+ _replace.put(Pair.create(Material.THIN_GLASS, (byte)0), new ItemStack(Material.STAINED_GLASS_PANE));
+ _replace.put(Pair.create(Material.WOOL, (byte)0), new ItemStack(Material.WOOL));
+ _replace.put(Pair.create(Material.CARPET, (byte)0), new ItemStack(Material.CARPET));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)0), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)1), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)2), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)3), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)4), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)5), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)6), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)7), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.RED_ROSE, (byte)8), new ItemStack(Material.RED_ROSE));
+ _replace.put(Pair.create(Material.COBBLE_WALL, (byte)0), new ItemStack(Material.COBBLE_WALL));
+ _replace.put(Pair.create(Material.JACK_O_LANTERN, (byte)0), new ItemStack(Material.GLOWSTONE));
+ _replace.put(Pair.create(Material.SMOOTH_BRICK, (byte)0), new ItemStack(Material.SMOOTH_BRICK));
+
+ UtilServer.RegisterEvents(this);
+ }
+
+ @SuppressWarnings("deprecation")
+ private Pair convert(ItemStack old)
+ {
+ if (old == null)
+ {
+ return Pair.create(old, false);
+ }
+ Pair pair = Pair.create(old.getType(), old.getData().getData());
+ if (!_replace.containsKey(pair))
+ {
+ return Pair.create(old, false);
+ }
+ ItemBuilder after = new ItemBuilder(_replace.get(pair));
+ if (after.getType() == Material.RED_ROSE)
+ {
+ after.setData((short)UtilMath.r(9));
+ }
+ else if (after.getType() == Material.COBBLE_WALL)
+ {
+ after.setData((short)1);
+ }
+ else if (after.getType() == Material.GLOWSTONE)
+ {
+ after.setData((short)0);
+ }
+ else if (after.getType() == Material.SMOOTH_BRICK)
+ {
+ after.setData(UtilMath.randomElement(new Short[] {1, 3}).shortValue());
+ }
+ else
+ {
+ after.setData(UtilMath.randomElement(DyeColor.values()).getWoolData());
+ }
+ after.setAmount(old.getAmount());
+
+ return Pair.create(after.build(), true);
+ }
+
+ @SuppressWarnings("deprecation")
+ public void open(Player player)
+ {
+ Inventory newInv = Bukkit.createInventory(player, 27, "Builder's Box");
+ ItemStack border = new ItemBuilder(Material.STAINED_GLASS_PANE).setData((short)DyeColor.GRAY.getWoolData()).setTitle(C.cRed + " ").build();
+ ItemStack button = new ItemBuilder(Material.STAINED_GLASS_PANE).setData((short)DyeColor.LIME.getWoolData()).setTitle(C.cGreenB + "Convert").build();
+ for (int i = 0; i < 27; i++)
+ {
+ if (i == 22)
+ {
+ newInv.setItem(i, button);
+ continue;
+ }
+ if (i < 9 || i > 17)
+ {
+ newInv.setItem(i, border);
+ }
+ }
+ player.openInventory(newInv);
+ }
+
+ @EventHandler
+ public void onClose(InventoryCloseEvent event)
+ {
+ InventoryView view = event.getView();
+ if (view.getTopInventory() != null)
+ {
+ Inventory top = view.getTopInventory();
+ if (top.getTitle().equals("Builder's Box"))
+ {
+ List items = new ArrayList<>();
+ for (int i = 9; i < 18; i++)
+ {
+ items.add(top.getItem(i));
+ }
+ if (items != null && !items.isEmpty());
+ {
+ int totalChanged = 0;
+ for (Pair pair : items.stream().map(this::convert).collect(Collectors.toList()))
+ {
+ if (pair.getLeft() == null)
+ {
+ continue;
+ }
+ if (pair.getRight())
+ {
+ totalChanged++;
+ }
+ event.getPlayer().getInventory().addItem(pair.getLeft());
+ }
+ if (totalChanged > 0)
+ {
+ ClansManager.getInstance().getInventoryManager().addItemToInventory((Player)event.getPlayer(), BoxType.BUILDER_BOX.getItemName(), -1);
+ UtilPlayer.message(event.getPlayer(), F.main("Builder's Box", "You have redeemed your box contents!"));
+ }
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onClick(InventoryClickEvent event)
+ {
+ if (event.getClickedInventory() != null && event.getClickedInventory().getTitle().equals("Builder's Box"))
+ {
+ if (event.getSlot() < 9 || event.getSlot() > 17)
+ {
+ event.setCancelled(true);
+ }
+ if (event.getSlot() == 22)
+ {
+ event.getWhoClicked().closeInventory();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/DyeBoxSpinner.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/DyeBoxSpinner.java
new file mode 100644
index 000000000..0186f6b56
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/boxes/extra/DyeBoxSpinner.java
@@ -0,0 +1,172 @@
+package mineplex.game.clans.clans.boxes.extra;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.bukkit.Bukkit;
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+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.common.util.UtilServer;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.boxes.BoxManager.BoxType;
+
+public class DyeBoxSpinner implements Listener
+{
+ private Player _player;
+ private Inventory _inv;
+ private int _step;
+ private List _items;
+
+ private boolean _givenRewards = false;
+
+ private DyeBoxSpinner(Player player)
+ {
+ _player = player;
+ _inv = Bukkit.createInventory(player, 27, "Dye Box");
+ _step = 0;
+ _items = new ArrayList<>();
+ buildGUI();
+ generateRewards();
+ player.openInventory(_inv);
+ Bukkit.getPluginManager().registerEvents(this, UtilServer.getPlugin());
+ }
+
+ /**
+ * Upper and lower bounds are inclusive
+ */
+ private int getRandom(int max, int min)
+ {
+ return UtilMath.r(max - min + 1) + min;
+ }
+
+ @SuppressWarnings("deprecation")
+ private void buildGUI()
+ {
+ ItemStack border = new ItemBuilder(Material.STAINED_GLASS_PANE).setData((short)DyeColor.GRAY.getWoolData()).setTitle(C.cRed + " ").build();
+ ItemStack fill = new ItemBuilder(Material.STAINED_GLASS_PANE).setData((short)DyeColor.BLACK.getWoolData()).setTitle(C.cRed + " ").build();
+ for (int i = 0; i < 27; i++)
+ {
+ if (i < 9 || i > 17)
+ {
+ _inv.setItem(i, border);
+ }
+ else
+ {
+ _inv.setItem(i, fill);
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private void generateRewards()
+ {
+ List commonColors = Arrays.asList(DyeColor.values()).stream().filter(c -> c != DyeColor.BLACK && c != DyeColor.WHITE).collect(Collectors.toList());
+ List rareColors = Arrays.asList(DyeColor.WHITE, DyeColor.BLACK);
+ for (int i = 1; i <= getRandom(9, 5); i++)
+ {
+ DyeColor color = null;
+ if (Math.random() <= 0.05)
+ {
+ color = UtilMath.randomElement(rareColors);
+ }
+ else
+ {
+ color = UtilMath.randomElement(commonColors);
+ }
+
+ _items.add(new ItemBuilder(Material.INK_SACK).setData(color.getDyeData()).setTitle(C.cGold + "Dye").build());
+ }
+ }
+
+ private void giveRewards()
+ {
+ if (_givenRewards)
+ {
+ return;
+ }
+ _givenRewards = true;
+ _player.closeInventory();
+ _items.forEach(_player.getInventory()::addItem);
+ UtilPlayer.message(_player, F.main("Dye Box", "You have redeemed your box contents!"));
+ }
+
+ @SuppressWarnings("deprecation")
+ private void progress()
+ {
+ if (_step == 0)
+ {
+ _step++;
+ return;
+ }
+ if (_step < 10)
+ {
+ int slot = 18 - _step;
+ if (Math.max(18, slot) - Math.min(18, slot) <= _items.size())
+ {
+ _inv.setItem(slot, new ItemBuilder(Material.STAINED_GLASS_PANE).setData((short)DyeColor.LIME.getWoolData()).setTitle(C.cRed + " ").build());
+ }
+ _step++;
+ return;
+ }
+ if (_step == 10)
+ {
+ int slot = 17;
+ for (int i = 0; i < _items.size(); i++)
+ {
+ _inv.setItem(slot, _items.get(i));
+ slot--;
+ }
+ _step++;
+ return;
+ }
+ }
+
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() == UpdateType.FASTEST)
+ {
+ if (_player.getOpenInventory() == null || _player.getOpenInventory().getTopInventory() == null || !_player.getOpenInventory().getTopInventory().getName().equals("Dye Box"))
+ {
+ HandlerList.unregisterAll(this);
+ giveRewards();
+ }
+ }
+ if (event.getType() == UpdateType.SEC)
+ {
+ progress();
+ }
+ }
+
+ @EventHandler
+ public void onClick(InventoryClickEvent event)
+ {
+ if (event.getWhoClicked().getEntityId() == _player.getEntityId())
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ public static void createSpinner(Player player)
+ {
+ ClansManager.getInstance().getInventoryManager().addItemToInventory(player, BoxType.DYE_BOX.getItemName(), -1);
+ new DyeBoxSpinner(player);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansAllyChatCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansAllyChatCommand.java
index b1723b719..fdbd287a4 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansAllyChatCommand.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansAllyChatCommand.java
@@ -2,10 +2,13 @@ package mineplex.game.clans.clans.commands;
import org.bukkit.entity.Player;
+import mineplex.core.Managers;
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.punish.Punish;
+import mineplex.core.punish.PunishClient;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
@@ -39,7 +42,16 @@ public class ClansAllyChatCommand extends CommandBase
{
ClanInfo clan = Plugin.getClanUtility().getClanByPlayer(caller);
if (clan == null) UtilPlayer.message(caller, F.main("Clans", "You are not in a Clan."));
- else Plugin.chatAlly(clan, caller, F.combine(args, 0, null, false));
+ else
+ {
+ PunishClient punishClient = Managers.get(Punish.class).GetClient(caller.getName());
+ if (punishClient != null && punishClient.IsMuted())
+ {
+ UtilPlayer.message(caller, F.main("Clans", "You cannot do this while muted!"));
+ return;
+ }
+ Plugin.chatAlly(clan, caller, F.combine(args, 0, null, false));
+ }
}
}
}
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansChatCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansChatCommand.java
index 36619c1ef..3ce97064c 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansChatCommand.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansChatCommand.java
@@ -2,10 +2,13 @@ package mineplex.game.clans.clans.commands;
import org.bukkit.entity.Player;
+import mineplex.core.Managers;
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.punish.Punish;
+import mineplex.core.punish.PunishClient;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
@@ -41,7 +44,15 @@ public class ClansChatCommand extends CommandBase
if (clan == null)
UtilPlayer.message(caller, F.main("Clans", "You are not in a Clan."));
else
+ {
+ PunishClient punishClient = Managers.get(Punish.class).GetClient(caller.getName());
+ if (punishClient != null && punishClient.IsMuted())
+ {
+ UtilPlayer.message(caller, F.main("Clans", "You cannot do this while muted!"));
+ return;
+ }
Plugin.chatClan(clan, caller, F.combine(args, 0, null, false));
+ }
}
}
}
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java
index 39511c874..adef219f9 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/commands/ClansCommand.java
@@ -549,6 +549,12 @@ public class ClansCommand extends CommandBase
UtilPlayer.message(caller, F.main("Clans", "The clan " + F.elem("Clan " + clan.getName()) + " is full and cannot be joined!"));
return;
}
+
+ if (clan.getAllies() > clan.getAlliesMaxWithMemberCountOf(clan.getSize() + 1))
+ {
+ UtilPlayer.message(caller, F.main("Clans", "You cannot join " + F.elem("Clan " + clan.getName()) + " until they remove some allies!"));
+ return;
+ }
ClanJoinEvent event = new ClanJoinEvent(clan, caller);
Bukkit.getPluginManager().callEvent(event);
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/ClanIcon.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/ClanIcon.java
index 078b469f7..118549e90 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/ClanIcon.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/ClanIcon.java
@@ -7,8 +7,8 @@ public enum ClanIcon
JOIN(Material.PRISMARINE, (byte) 1),
LEAVE(Material.PRISMARINE, (byte) 2),
TERRITORY(Material.PRISMARINE, (byte) 0),
- MEMBER(Material.SAND, (byte) 1),
- COMMANDS(Material.RED_SANDSTONE, (byte) 0),
+ MEMBER(Material.WATER_BUCKET, (byte) 0),
+ COMMANDS(Material.LAVA_BUCKET, (byte) 0),
ENERGY(Material.SEA_LANTERN, (byte) 0),
CASTLE(Material.RECORD_9, (byte) 0),
WAR(Material.RECORD_11, (byte) 0),
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/button/ClanTerritoryButton.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/button/ClanTerritoryButton.java
index 363c78f01..ebcff0611 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/button/ClanTerritoryButton.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/button/ClanTerritoryButton.java
@@ -9,6 +9,7 @@ import org.bukkit.event.inventory.ClickType;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
+import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilWorld;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClanRole;
@@ -27,12 +28,18 @@ public class ClanTerritoryButton extends ClanButton
{
if (UtilServer.CallEvent(new ClansButtonClickEvent(player, ClansButtonClickEvent.ButtonType.Territory)).isCancelled())
return;
-// if (_clansManager.getNetherManager().isInNether(player))
-// {
-// _clansManager.message(player, "You are not allowed to do anything with Territory while in " + F.clansNether("The Nether") + ".");
-// player.closeInventory();
-// return;
-// }
+ if (_clansManager.getNetherManager().isInNether(player))
+ {
+ UtilPlayer.message(player, F.main(_clansManager.getNetherManager().getName(), "You cannot manage your clan's territory while in " + F.clansNether("The Nether") + "!"));
+ player.closeInventory();
+ return;
+ }
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ UtilPlayer.message(player, F.main(_clansManager.getWorldEvent().getRaidManager().getName(), "You cannot manage your clan's territory while in a raid!"));
+ player.closeInventory();
+ return;
+ }
if (clickType == ClickType.LEFT)
{
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java
index 7db99c36b..ee6361d72 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/gui/page/ClanMainPage.java
@@ -361,4 +361,4 @@ public class ClanMainPage extends ClanPageBase
addButton(slot, item, new ClanMemeberButton(getShop(), getPlugin(), getPlayer(), guiInfo, guiRole, this, clansPlayer.getPlayerName()));
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/LootManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/LootManager.java
index a322d8041..949723a3a 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/LootManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/LootManager.java
@@ -4,6 +4,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
import mineplex.game.clans.economy.GoldManager;
import mineplex.game.clans.items.GearManager;
import mineplex.core.common.weight.WeightSet;
@@ -87,8 +88,9 @@ public class LootManager
private void populateRare()
{
// Gear
- _rareSet.add(90, new GearLoot(_gearManager));
+ _rareSet.add(70, new GearLoot(_gearManager));
_rareSet.add(10, new GoldTokenLoot(50000, 100000));
+ _rareSet.add(20, new MountLoot(1, 3, MountType.values()));
}
public void dropCommon(Location location)
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/MountLoot.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/MountLoot.java
new file mode 100644
index 000000000..65fe0c074
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/loot/MountLoot.java
@@ -0,0 +1,45 @@
+package mineplex.game.clans.clans.loot;
+
+import org.bukkit.Color;
+import org.bukkit.FireworkEffect.Type;
+import org.bukkit.Location;
+import org.bukkit.inventory.ItemStack;
+
+import mineplex.core.common.util.UtilFirework;
+import mineplex.core.common.util.UtilMath;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+import mineplex.game.clans.clans.mounts.MountClaimToken;
+
+public class MountLoot implements ILoot
+{
+ private int _minStars, _maxStars;
+ private MountType[] _types;
+
+ public MountLoot(int minStars, int maxStars, MountType... types)
+ {
+ _minStars = Math.max(minStars, 1);
+ _maxStars = Math.min(maxStars, 3);
+ if (types.length == 0)
+ {
+ _types = MountType.values();
+ }
+ else
+ {
+ _types = types;
+ }
+ }
+
+ @Override
+ public void dropLoot(Location location)
+ {
+ MountClaimToken token = new MountClaimToken(UtilMath.rRange(_minStars, _maxStars), UtilMath.rRange(_minStars, _maxStars), UtilMath.rRange(_minStars, _maxStars), UtilMath.randomElement(_types));
+ UtilFirework.playFirework(location.clone().add(0, 3, 0), Type.BALL, Color.SILVER, true, false);
+ location.getWorld().dropItemNaturally(location.clone().add(0, 3, 0), token.toItem());
+ }
+
+ @Override
+ public ItemStack getItemStack()
+ {
+ return new MountClaimToken(UtilMath.rRange(_minStars, _maxStars), UtilMath.rRange(_minStars, _maxStars), UtilMath.rRange(_minStars, _maxStars), UtilMath.randomElement(_types)).toItem();
+ }
+}
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java
index 69835e4ae..07ac8f1cf 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/map/ItemMapRenderer.java
@@ -1,20 +1,6 @@
package mineplex.game.clans.clans.map;
import java.awt.Color;
-import java.util.List;
-
-import mineplex.core.common.util.UtilTime;
-import mineplex.core.recharge.Recharge;
-import mineplex.game.clans.clans.ClanInfo;
-import mineplex.game.clans.clans.ClansUtility;
-import mineplex.game.clans.clans.worldevent.WorldEventManager;
-import mineplex.game.clans.tutorial.TutorialManager;
-import mineplex.game.clans.tutorial.TutorialRegion;
-import mineplex.game.clans.tutorial.TutorialType;
-import mineplex.game.clans.tutorial.map.TutorialMapManager;
-import mineplex.game.clans.tutorial.tutorials.clans.ClansMainTutorial;
-import mineplex.minecraft.game.core.boss.EventState;
-import mineplex.minecraft.game.core.boss.WorldEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -26,6 +12,14 @@ import org.bukkit.map.MapPalette;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
+import mineplex.core.common.util.UtilTime;
+import mineplex.game.clans.clans.ClanInfo;
+import mineplex.game.clans.clans.ClansUtility;
+import mineplex.game.clans.clans.worldevent.WorldEventManager;
+import mineplex.game.clans.clans.worldevent.api.EventState;
+import mineplex.game.clans.clans.worldevent.api.WorldEvent;
+import mineplex.game.clans.tutorial.TutorialManager;
+
public class ItemMapRenderer extends MapRenderer
{
private ItemMapManager _manager;
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/Mount.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/Mount.java
new file mode 100644
index 000000000..093631e9b
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/Mount.java
@@ -0,0 +1,370 @@
+package mineplex.game.clans.clans.mounts;
+
+import java.util.function.Consumer;
+
+import org.bukkit.ChatColor;
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftHorse;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Horse.Color;
+import org.bukkit.entity.Horse.Style;
+import org.bukkit.entity.Horse.Variant;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import mineplex.core.common.TriConsumer;
+import mineplex.core.common.util.C;
+import mineplex.core.common.util.UtilParticle;
+import mineplex.core.common.util.UtilParticle.ParticleType;
+import mineplex.core.common.util.UtilParticle.ViewDist;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.common.util.UtilTime;
+import mineplex.core.disguise.disguises.DisguiseBase;
+import mineplex.core.disguise.disguises.DisguiseCow;
+import mineplex.core.disguise.disguises.DisguiseSheep;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.game.clans.clans.ClansManager;
+import net.minecraft.server.v1_8_R3.GenericAttributes;
+
+public class Mount
+{
+ private static final long HIT_REGEN_COOLDOWN = 30000;
+
+ private Player _owner;
+ private CraftHorse _entity;
+ private SkinType _skin;
+ private final int _strength;
+ private long _lastHit;
+ private int _hits;
+
+ public Mount(Player owner, CraftHorse entity, SkinType skin, int strength)
+ {
+ _owner = owner;
+ _entity = entity;
+ _skin = skin;
+ _strength = strength;
+ _lastHit = System.currentTimeMillis();
+ _hits = 0;
+ }
+
+ public Player getOwner()
+ {
+ return _owner;
+ }
+
+ public CraftHorse getEntity()
+ {
+ return _entity;
+ }
+
+ public void update()
+ {
+ if (_skin != null)
+ {
+ _skin.onUpdate(_entity);
+ }
+ if (UtilTime.elapsed(_lastHit, HIT_REGEN_COOLDOWN) && _hits > 0)
+ {
+ _hits--;
+ _lastHit = System.currentTimeMillis();
+ }
+ }
+
+ public void despawn(boolean forced)
+ {
+ UtilServer.CallEvent(new MountDespawnEvent(this, forced));
+ _entity.getInventory().setSaddle(null);
+ _entity.getInventory().setArmor(null);
+ for (ItemStack item : _entity.getInventory().getContents())
+ {
+ if (item == null || item.getType() == Material.AIR)
+ {
+ continue;
+ }
+ _entity.getWorld().dropItem(_entity.getLocation(), item);
+ }
+ _entity.remove();
+ }
+
+ public void handleHit()
+ {
+ _hits++;
+ if (_hits == _strength)
+ {
+ despawn(true);
+ }
+ }
+
+ public static enum SkinType
+ {
+ INFERNAL_HORROR(1, "Clans Infernal Horror Mount Skin", C.cRed + "Infernal Horror", Material.BONE, Color.BLACK, Variant.SKELETON_HORSE, Style.BLACK_DOTS, horse -> {}, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.FLAME, horse.getLocation().add(0, 1, 0),
+ 0.25f, 0.25f, 0.25f, 0, 2,ViewDist.NORMAL);
+ }, MountType.HORSE),
+ GLACIAL_STEED(2, "Clans Glacial Steed Mount Skin", C.cGray + "Glacial Steed", Material.SNOW_BALL, Color.WHITE, Variant.HORSE, Style.WHITE, horse -> {}, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.SNOW_SHOVEL, horse.getLocation().add(0, 1, 0),
+ 0.25f, 0.25f, 0.25f, 0.1f, 4, ViewDist.NORMAL);
+ }, MountType.HORSE),
+ ZOMBIE_HORSE(3, "Clans Zombie Horse Mount Skin", C.cDGray + "Zombie Horse", Material.ROTTEN_FLESH, Color.BLACK, Variant.UNDEAD_HORSE, Style.BLACK_DOTS, horse -> {}, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.FOOTSTEP, horse.getLocation(),
+ null, 0, 1, ViewDist.NORMAL);
+ }, MountType.HORSE),
+ @SuppressWarnings("deprecation")
+ RAINBOW_SHEEP(4, "Clans Rainbow Sheep Mount Skin", C.cGreen + "Rainbow " + C.cAqua + "Sheep", new ItemBuilder(Material.WOOL).setData(DyeColor.RED.getWoolData()).build(),Color.WHITE, Variant.HORSE, Style.NONE, horse ->
+ {
+ DisguiseSheep disguise = new DisguiseSheep(horse);
+ disguise.setName(horse.getCustomName());
+ ClansManager.getInstance().getDisguiseManager().disguise(disguise);
+ }, horse ->
+ {
+ DisguiseBase base = ClansManager.getInstance().getDisguiseManager().getActiveDisguise(horse);
+ if (base == null || !(base instanceof DisguiseSheep))
+ {
+ return;
+ }
+
+ DisguiseSheep sheep = (DisguiseSheep)base;
+
+ if (horse.getTicksLived() % 4 == 0) sheep.setColor(DyeColor.RED);
+ else if (horse.getTicksLived() % 4 == 1) sheep.setColor(DyeColor.YELLOW);
+ else if (horse.getTicksLived() % 4 == 2) sheep.setColor(DyeColor.GREEN);
+ else if (horse.getTicksLived() % 4 == 3) sheep.setColor(DyeColor.BLUE);
+ }, MountType.HORSE),
+ ROYAL_STEED(5, "Clans Royal Steed Mount Skin", C.cGold + "Royal Steed", Material.DIAMOND_BARDING, Color.WHITE, Variant.HORSE, Style.WHITE, horse ->
+ {
+ horse.getInventory().setArmor(new ItemBuilder(Material.DIAMOND_BARDING).setTitle(C.cGoldB + "Royal Armor").build());
+ }, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.BLOCK_DUST.getParticle(Material.GOLD_BLOCK, 0), horse.getLocation().add(0, 1, 0),
+ 0.25f, 0.25f, 0.25f, 0, 3, ViewDist.NORMAL);
+ }, MountType.HORSE),
+ ROYAL_GUARD_STEED(6, "Clans Royal Guard Steed Mount Skin", C.cGray + "Royal Guard's Steed", Material.GOLD_BARDING, Color.BLACK, Variant.HORSE, Style.NONE, horse ->
+ {
+ horse.getInventory().setArmor(new ItemBuilder(Material.GOLD_BARDING).setTitle(C.cGoldB + "Guardian Armor").build());
+ }, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.BLOCK_DUST.getParticle(Material.IRON_BLOCK, 0), horse.getLocation().add(0, 1, 0),
+ 0.25f, 0.25f, 0.25f, 0, 3, ViewDist.NORMAL);
+ }, MountType.HORSE),
+ KNIGHT_STEED(7, "Clans Knight Steed Mount Skin", C.cDRed + "Knight's Steed", Material.IRON_BARDING, Color.GRAY, Variant.HORSE, Style.NONE, horse ->
+ {
+ horse.getInventory().setArmor(new ItemBuilder(Material.IRON_BARDING).setTitle(C.cGoldB + "Knightly Armor").build());
+ }, horse ->
+ {
+ UtilParticle.PlayParticleToAll(ParticleType.ICON_CRACK.getParticle(Material.APPLE, 0), horse.getLocation().add(0, 1, 0),
+ 0.25f, 0.25f, 0.25f, 0, 3, ViewDist.NORMAL);
+ }, MountType.HORSE),
+ COW(8, "Clans Cow Mount Skin", C.cWhite + "Cow", Material.MILK_BUCKET, Color.WHITE, Variant.HORSE, Style.NONE, horse ->
+ {
+ DisguiseCow disguise = new DisguiseCow(horse);
+ disguise.setName(horse.getCustomName());
+ ClansManager.getInstance().getDisguiseManager().disguise(disguise);
+ }, horse -> {}, MountType.HORSE),
+ SHEEP(9, "Clans Sheep Mount Skin", C.cWhite + "Sheep", Material.WOOL, Color.WHITE, Variant.HORSE, Style.NONE, horse ->
+ {
+ DisguiseSheep disguise = new DisguiseSheep(horse);
+ disguise.setName(horse.getCustomName());
+ ClansManager.getInstance().getDisguiseManager().disguise(disguise);
+ }, horse -> {}, MountType.HORSE),
+ TRUSTY_MULE(10, "Clans Trusty Mule Mount Skin", C.cBlue + "Trusty Mule", Material.APPLE, Color.BROWN, Variant.MULE, Style.NONE, horse -> {}, horse -> {}, MountType.DONKEY)
+ ;
+
+ private final int _id;
+ private final String _packageName;
+ private final String _displayName;
+ private final ItemStack _baseDisplayItem;
+ private final Color _color;
+ private final Variant _variant;
+ private final Style _style;
+ private final Consumer _onSpawn, _onUpdate;
+ private final MountType[] _possibleTypes;
+
+ private SkinType(int id, String packageName, String displayName, Material displayType, Color color, Variant variant, Style style, Consumer onSpawn, Consumer onUpdate, MountType... possibleTypes)
+ {
+ this(id, packageName, displayName, new ItemStack(displayType), color, variant, style, onSpawn, onUpdate, possibleTypes);
+ }
+
+ private SkinType(int id, String packageName, String displayName, ItemStack baseDisplayItem, Color color, Variant variant, Style style, Consumer onSpawn, Consumer onUpdate, MountType... possibleTypes)
+ {
+ _id = id;
+ _packageName = packageName;
+ _displayName = displayName;
+ _baseDisplayItem = baseDisplayItem;
+ _color = color;
+ _variant = variant;
+ _style = style;
+ _onSpawn = onSpawn;
+ _onUpdate = onUpdate;
+ _possibleTypes = possibleTypes;
+ }
+
+ public int getId()
+ {
+ return _id;
+ }
+
+ public String getPackageName()
+ {
+ return _packageName;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+
+ public ItemStack getBaseDisplay()
+ {
+ return _baseDisplayItem;
+ }
+
+ public Color getColor()
+ {
+ return _color;
+ }
+
+ public Variant getVariant()
+ {
+ return _variant;
+ }
+
+ public Style getStyle()
+ {
+ return _style;
+ }
+
+ public void onSpawn(CraftHorse horse)
+ {
+ _onSpawn.accept(horse);
+ }
+
+ public void onUpdate(CraftHorse horse)
+ {
+ _onUpdate.accept(horse);
+ }
+
+ public MountType[] getPossibleTypes()
+ {
+ return _possibleTypes;
+ }
+
+ public static SkinType getFromId(int id)
+ {
+ for (SkinType type : SkinType.values())
+ {
+ if (type.getId() == id)
+ {
+ return type;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ public static enum MountType
+ {
+ HORSE(1, C.cWhite + "Horse", Material.IRON_BARDING, (owner, skin, stats) ->
+ {
+ CraftHorse horse = (CraftHorse) owner.getWorld().spawnEntity(owner.getLocation(), EntityType.HORSE);
+ horse.setAdult();
+ horse.setAgeLock(true);
+ horse.setBreed(false);
+ horse.setCustomNameVisible(true);
+ horse.setCustomName(owner.getName() + "'s " + (skin == null ? "Horse" : ChatColor.stripColor(skin.getDisplayName())));
+ if (skin != null)
+ {
+ horse.setVariant(skin.getVariant());
+ horse.setColor(skin.getColor());
+ horse.setStyle(skin.getStyle());
+ skin.onSpawn(horse);
+ }
+ horse.setTamed(true);
+ horse.getInventory().setSaddle(new ItemStack(Material.SADDLE));
+ horse.setOwner(owner);
+ horse.setJumpStrength(MountManager.getJump(stats.JumpStars));
+ horse.getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(MountManager.getSpeed(stats.SpeedStars));
+ //horse.setPassenger(owner);
+ Mount mount = new Mount(owner, horse, skin, MountManager.getStrength(stats.StrengthStars));
+ UtilServer.CallEvent(new MountSpawnEvent(mount));
+ }),
+ DONKEY(2, C.cWhite + "Donkey", Material.GOLD_BARDING, (owner, skin, stats) ->
+ {
+ CraftHorse horse = (CraftHorse) owner.getWorld().spawnEntity(owner.getLocation(), EntityType.HORSE);
+ horse.setAdult();
+ horse.setAgeLock(true);
+ horse.setBreed(false);
+ horse.setCustomNameVisible(true);
+ horse.setCustomName(owner.getName() + "'s " + (skin == null ? "Donkey" : ChatColor.stripColor(skin.getDisplayName())));
+ if (skin != null)
+ {
+ horse.setVariant(skin.getVariant());
+ skin.onSpawn(horse);
+ }
+ else
+ {
+ horse.setVariant(Variant.DONKEY);
+ }
+ horse.setTamed(true);
+ horse.getInventory().setSaddle(new ItemStack(Material.SADDLE));
+ horse.setOwner(owner);
+ horse.setJumpStrength(MountManager.getJump(stats.JumpStars));
+ horse.getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(MountManager.getSpeed(stats.SpeedStars));
+ horse.setCarryingChest(true);
+ //horse.setPassenger(owner);
+ Mount mount = new Mount(owner, horse, skin, MountManager.getStrength(stats.StrengthStars));
+ UtilServer.CallEvent(new MountSpawnEvent(mount));
+ })
+ ;
+
+ private final int _id;
+ private final String _displayName;
+ private final Material _displayType;
+ private final TriConsumer _spawnHandler;
+
+ private MountType(int id, String displayName, Material displayType, TriConsumer spawnHandler)
+ {
+ _id = id;
+ _displayName = displayName;
+ _displayType = displayType;
+ _spawnHandler = spawnHandler;
+ }
+
+ public int getId()
+ {
+ return _id;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+
+ public Material getDisplayType()
+ {
+ return _displayType;
+ }
+
+ public void spawn(Player owner, SkinType skinType, MountStatToken statToken)
+ {
+ _spawnHandler.accept(owner, skinType, statToken);
+ }
+
+ public static MountType getFromId(int id)
+ {
+ for (MountType type : MountType.values())
+ {
+ if (type.getId() == id)
+ {
+ return type;
+ }
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountClaimToken.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountClaimToken.java
new file mode 100644
index 000000000..63c0b11d6
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountClaimToken.java
@@ -0,0 +1,103 @@
+package mineplex.game.clans.clans.mounts;
+
+import org.bukkit.ChatColor;
+import org.bukkit.inventory.ItemStack;
+
+import mineplex.core.common.util.C;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+
+public class MountClaimToken
+{
+ private final String STAR = "✩";
+
+ public final int JumpStars;
+ public final int SpeedStars;
+ public final int StrengthStars;
+ public final MountType Type;
+
+ public MountClaimToken(int jumpStars, int speedStars, int strengthStars, MountType type)
+ {
+ JumpStars = jumpStars;
+ SpeedStars = speedStars;
+ StrengthStars = strengthStars;
+ Type = type;
+ }
+
+ public ItemStack toItem()
+ {
+ ItemBuilder builder = new ItemBuilder(Type.getDisplayType());
+ builder.setTitle(Type.getDisplayName() + " Mount Token");
+ String strength = C.cYellow;
+ for (int i = 0; i < StrengthStars; i++)
+ {
+ strength += STAR;
+ }
+ builder.addLore(C.cPurple + "Strength: " + strength);
+ String speed = C.cYellow;
+ for (int i = 0; i < SpeedStars; i++)
+ {
+ speed += STAR;
+ }
+ builder.addLore(C.cPurple + "Speed: " + speed);
+ String jump = C.cYellow;
+ for (int i = 0; i < JumpStars; i++)
+ {
+ jump += STAR;
+ }
+ builder.addLore(C.cPurple + "Jump: " + jump);
+ builder.addLore(C.cRed);
+ builder.addLore(C.cDGreen + "Right-Click While Holding to Consume");
+
+ return builder.build();
+ }
+
+ public static MountClaimToken fromItem(ItemStack item)
+ {
+ if (!item.hasItemMeta() || !item.getItemMeta().hasLore())
+ {
+ return null;
+ }
+
+ MountType type = null;
+ for (MountType check : MountType.values())
+ {
+ if (check.getDisplayType() == item.getType())
+ {
+ type = check;
+ break;
+ }
+ }
+ if (type == null)
+ {
+ return null;
+ }
+
+ int strength = -1;
+ int speed = -1;
+ int jump = -1;
+
+ for (String lore : item.getItemMeta().getLore())
+ {
+ if (ChatColor.stripColor(lore).startsWith("Strength: "))
+ {
+ strength = ChatColor.stripColor(lore).replace("Strength: ", "").length();
+ }
+ if (ChatColor.stripColor(lore).startsWith("Speed: "))
+ {
+ speed = ChatColor.stripColor(lore).replace("Speed: ", "").length();
+ }
+ if (ChatColor.stripColor(lore).startsWith("Jump: "))
+ {
+ jump = ChatColor.stripColor(lore).replace("Jump: ", "").length();
+ }
+ }
+
+ if (strength <= 0 || speed <= 0 || jump <= 0)
+ {
+ return null;
+ }
+
+ return new MountClaimToken(strength, speed, jump, type);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountDespawnEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountDespawnEvent.java
new file mode 100644
index 000000000..9d4745116
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountDespawnEvent.java
@@ -0,0 +1,41 @@
+package mineplex.game.clans.clans.mounts;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+/**
+ * Event called before a mount despawns
+ */
+public class MountDespawnEvent extends Event
+{
+ private static final HandlerList handlers = new HandlerList();
+
+ private final Mount _mount;
+ private final boolean _forced;
+
+ public MountDespawnEvent(Mount mount, boolean forced)
+ {
+ _mount = mount;
+ _forced = forced;
+ }
+
+ public Mount getMount()
+ {
+ return _mount;
+ }
+
+ public boolean isForced()
+ {
+ return _forced;
+ }
+
+ public HandlerList getHandlers()
+ {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList()
+ {
+ return handlers;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountManager.java
new file mode 100644
index 000000000..2460ffea9
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountManager.java
@@ -0,0 +1,528 @@
+package mineplex.game.clans.clans.mounts;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+import java.util.WeakHashMap;
+
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftHorse;
+import org.bukkit.entity.Horse;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.inventory.HorseInventory;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import mineplex.core.MiniDbClientPlugin;
+import mineplex.core.account.CoreClientManager;
+import mineplex.core.command.CommandBase;
+import mineplex.core.common.Pair;
+import mineplex.core.common.Rank;
+import mineplex.core.common.util.F;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilEvent;
+import mineplex.core.common.util.UtilEvent.ActionType;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilTime;
+import mineplex.core.donation.DonationManager;
+import mineplex.core.recharge.Recharge;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+import mineplex.game.clans.clans.mounts.Mount.SkinType;
+import mineplex.game.clans.clans.mounts.gui.MountShop;
+import mineplex.game.clans.spawn.Spawn;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+import mineplex.serverdata.Utility;
+
+public class MountManager extends MiniDbClientPlugin
+{
+ private static final double[] JUMP_STARS = {0.8, 1, 1.2};
+ private static final double[] SPEED_STARS = {0.2, 0.27, 0.33};
+ private static final int[] STRENGTH_STARS = {1, 2, 3};
+
+ private static final long SUMMON_WARMUP = 5000;
+ private static final long FORCED_COOLDOWN = 120 * 1000;
+ private static final long MAX_TIME_DISMOUNTED = 30000;
+
+ private static final int MAX_PER_TYPE = 3;
+
+ private final MountRepository _repository;
+ private final DonationManager _donationManager;
+
+ private final Map _spawnedMounts = new HashMap<>();
+ private final Map> _summoning = new WeakHashMap<>();
+
+ public MountManager(JavaPlugin plugin, CoreClientManager clientManager, DonationManager donationManager)
+ {
+ super("Clans Mount Manager", plugin, clientManager);
+
+ _repository = new MountRepository(plugin, this);
+ _donationManager = donationManager;
+
+ final MountShop shop = new MountShop(this);
+
+ addCommand(new CommandBase(this, Rank.ALL, "mounts", "mount")
+ {
+ @Override
+ public void Execute(Player caller, String[] args)
+ {
+ shop.attemptShopOpen(caller);
+ }
+ });
+
+ addCommand(new CommandBase(this, Rank.ADMIN, "givemount")
+ {
+ @Override
+ public void Execute(Player caller, String[] args)
+ {
+ if (args.length < 4)
+ {
+ UtilPlayer.message(caller, F.main(getName(), "Usage: /" + _aliasUsed + " "));
+ return;
+ }
+
+ Integer speed = 0;
+ Integer jump = 0;
+ Integer strength = 0;
+ MountType type = null;
+
+ try
+ {
+ speed = Integer.parseInt(args[0]);
+ }
+ catch (Exception e)
+ {
+ UtilPlayer.message(caller, F.main(getName(), "Invalid speed!"));
+ return;
+ }
+
+ try
+ {
+ jump = Integer.parseInt(args[1]);
+ }
+ catch (Exception e)
+ {
+ UtilPlayer.message(caller, F.main(getName(), "Invalid jump!"));
+ return;
+ }
+
+ try
+ {
+ strength = Integer.parseInt(args[2]);
+ }
+ catch (Exception e)
+ {
+ UtilPlayer.message(caller, F.main(getName(), "Invalid strength!"));
+ return;
+ }
+
+ try
+ {
+ type = MountType.valueOf(args[3]);
+ }
+ catch (Exception e)
+ {
+ UtilPlayer.message(caller, F.main(getName(), "Invalid type!"));
+ return;
+ }
+
+ caller.getInventory().addItem(new MountClaimToken(jump, speed, strength, type).toItem());
+ }
+ });
+ }
+
+ public DonationManager getDonationManager()
+ {
+ return _donationManager;
+ }
+
+ public MountRepository getRepository()
+ {
+ return _repository;
+ }
+
+ @Override
+ public void disable()
+ {
+ _summoning.clear();
+ _spawnedMounts.keySet().forEach(CraftHorse::remove);
+ _spawnedMounts.clear();
+ }
+
+ public boolean summonMount(Player player, MountToken token)
+ {
+ if (_summoning.containsKey(player))
+ {
+ UtilPlayer.message(player, F.main(getName(), "You are already summoning a mount!"));
+ return false;
+ }
+ if (Spawn.getInstance().isSafe(player.getLocation()))
+ {
+ UtilPlayer.message(player, F.main(getName(), "You cannot summon a mount in safezones!"));
+ return false;
+ }
+ if (ClansManager.getInstance().getNetherManager().isInNether(player))
+ {
+ UtilPlayer.message(player, F.main(getName(), "You cannot summon a mount in the Nether!"));
+ return false;
+ }
+ if (ClansManager.getInstance().getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ UtilPlayer.message(player, F.main(getName(), "You cannot summon a mount inside a raid!"));
+ return false;
+ }
+ if (!Recharge.Instance.usable(player, "Mount Spawn Delay"))
+ {
+ UtilPlayer.message(player, F.main(getName(), "You cannot summon a mount so soon after your last one was forcibly despawned!"));
+ return false;
+ }
+ _spawnedMounts.values().stream().filter(mount -> mount.getOwner().getEntityId() == player.getEntityId()).findFirst().ifPresent(mount -> mount.despawn(false));
+ _summoning.put(player, Pair.create(System.currentTimeMillis(), token));
+ UtilPlayer.message(player, F.main(getName(), "You are now summoning your mount! Please remain still for 5 seconds!"));
+ return true;
+ }
+
+ public void giveMount(Player player, MountType type)
+ {
+ Pair tokens = Get(player).grantMount(type);
+ _repository.saveMount(ClientManager.getAccountId(player), tokens.getLeft(), tokens.getRight());
+ }
+
+ public void giveMount(Player player, MountClaimToken token)
+ {
+ Pair tokens = Get(player).grantMount(token.Type, token.SpeedStars, token.JumpStars, token.StrengthStars);
+ _repository.saveMount(ClientManager.getAccountId(player), tokens.getLeft(), tokens.getRight());
+ }
+
+ public void removeMountToken(Player player, MountToken token, Runnable after)
+ {
+ getRepository().deleteMount(token, id ->
+ {
+ Get(player).removeMount(id.intValue());
+ Pair summonPair = _summoning.get(player);
+ if (summonPair != null)
+ {
+ if (summonPair.getRight().Id == id)
+ {
+ UtilEnt.addFlag(player, "REMOVED_MOUNT_TOKEN");
+ }
+ }
+ after.run();
+ });
+ }
+
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() == UpdateType.TICK)
+ {
+ Iterator> mountIterator = _spawnedMounts.entrySet().iterator();
+ while (mountIterator.hasNext())
+ {
+ Entry entry = mountIterator.next();
+ if (entry.getKey().isDead() || !entry.getKey().isValid())
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ if (entry.getValue().getOwner().isDead() || !entry.getValue().getOwner().isValid() || !entry.getValue().getOwner().isOnline())
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ if (Spawn.getInstance().isSafe(entry.getKey().getLocation()))
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ if (ClansManager.getInstance().getNetherManager().isInNether(entry.getKey().getLocation()))
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ if (ClansManager.getInstance().getWorldEvent().getRaidManager().isInRaid(entry.getKey().getLocation()))
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ if (entry.getKey().getPassenger() == null)
+ {
+ if (UtilEnt.GetMetadata(entry.getKey(), "DISMOUNT_TIME") != null)
+ {
+ Long dismount = (Long) UtilEnt.GetMetadata(entry.getKey(), "DISMOUNT_TIME");
+ if (UtilTime.elapsed(dismount.longValue(), MAX_TIME_DISMOUNTED))
+ {
+ mountIterator.remove();
+ entry.getValue().despawn(false);
+ continue;
+ }
+ }
+ else
+ {
+ UtilEnt.SetMetadata(entry.getKey(), "DISMOUNT_TIME", System.currentTimeMillis());
+ }
+ }
+ else
+ {
+ UtilEnt.removeMetadata(entry.getKey(), "DISMOUNT_TIME");
+ }
+ entry.getValue().update();
+ }
+
+ Iterator>> summoningIterator = _summoning.entrySet().iterator();
+ while (summoningIterator.hasNext())
+ {
+ Entry> entry = summoningIterator.next();
+ if (UtilEnt.hasFlag(entry.getKey(), "REMOVED_MOUNT_TOKEN"))
+ {
+ summoningIterator.remove();
+ UtilEnt.removeFlag(entry.getKey(), "REMOVED_MOUNT_TOKEN");
+ continue;
+ }
+ if (UtilTime.elapsed(entry.getValue().getLeft(), SUMMON_WARMUP))
+ {
+ summoningIterator.remove();
+ if (entry.getKey().isDead() || !entry.getKey().isValid() || !entry.getKey().isOnline())
+ {
+ continue;
+ }
+ if (Spawn.getInstance().isSafe(entry.getKey().getLocation()))
+ {
+ continue;
+ }
+ if (ClansManager.getInstance().getNetherManager().isInNether(entry.getKey().getLocation()))
+ {
+ continue;
+ }
+ if (ClansManager.getInstance().getWorldEvent().getRaidManager().isInRaid(entry.getKey().getLocation()))
+ {
+ continue;
+ }
+ entry.getValue().getRight().Type.spawn(entry.getKey(), entry.getValue().getRight().Skin, Get(entry.getKey()).getStatToken(entry.getValue().getRight()));
+ continue;
+ }
+ if (UtilEnt.hasFlag(entry.getKey(), "MOVED_WHILE_SUMMONING_MOUNT"))
+ {
+ summoningIterator.remove();
+ UtilEnt.removeFlag(entry.getKey(), "MOVED_WHILE_SUMMONING_MOUNT");
+ UtilPlayer.message(entry.getKey(), F.main(getName(), "You have stopped summoning your mount as you have moved!"));
+ continue;
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent event)
+ {
+ if (_summoning.containsKey(event.getPlayer()) && !UtilEnt.hasFlag(event.getPlayer(), "MOVED_WHILE_SUMMONING_MOUNT"))
+ {
+ Block from = event.getFrom().getBlock();
+ Block to = event.getTo().getBlock();
+
+ if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ())
+ {
+ return;
+ }
+ UtilEnt.addFlag(event.getPlayer(), "MOVED_WHILE_SUMMONING_MOUNT");
+ }
+ }
+
+ @EventHandler
+ public void onSummon(MountSpawnEvent event)
+ {
+ _spawnedMounts.put(event.getMount().getEntity(), event.getMount());
+ UtilPlayer.message(event.getMount().getOwner(), F.main(getName(), "Your mount has spawned!"));
+ }
+
+ @EventHandler
+ public void onDespawn(MountDespawnEvent event)
+ {
+ _spawnedMounts.remove(event.getMount().getEntity());
+ event.getMount().getEntity().eject();
+ event.getMount().getEntity().remove();
+ UtilPlayer.message(event.getMount().getOwner(), F.main(getName(), "Your mount has despawned!"));
+ if (event.isForced())
+ {
+ Recharge.Instance.use(event.getMount().getOwner(), "Mount Spawn Delay", FORCED_COOLDOWN, false, false);
+ }
+ }
+
+ @EventHandler
+ public void onUseToken(PlayerInteractEvent event)
+ {
+ if (!UtilEvent.isAction(event, ActionType.R))
+ {
+ return;
+ }
+ if (event.getItem() == null)
+ {
+ return;
+ }
+ MountClaimToken token = MountClaimToken.fromItem(event.getItem());
+ if (token == null)
+ {
+ return;
+ }
+
+ event.setCancelled(true);
+
+ if (Get(event.getPlayer()).getAmountOwned(token.Type) >= MAX_PER_TYPE)
+ {
+ UtilPlayer.message(event.getPlayer(), F.main(getName(), "You have reached the maximum amount of that type of mount!"));
+ return;
+ }
+
+ giveMount(event.getPlayer(), token);
+ UtilPlayer.message(event.getPlayer(), F.main(getName(), "You have redeemed your mount!"));
+ event.getPlayer().getInventory().setItemInHand(null);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void handleHorseHits(CustomDamageEvent event)
+ {
+ if (event.GetDamageeEntity() == null || !(event.GetDamageeEntity() instanceof Horse))
+ {
+ return;
+ }
+ Mount mount = _spawnedMounts.get(event.GetDamageeEntity());
+ if (mount == null)
+ {
+ return;
+ }
+ if (event.GetDamagerPlayer(true) != null && event.GetDamagerPlayer(true).getEntityId() == mount.getOwner().getEntityId())
+ {
+ event.SetCancelled("Damaging own mount");
+ mount.despawn(false);
+ return;
+ }
+ event.setDamagee(mount.getOwner());
+ if (event.GetCause() != DamageCause.FALL)
+ {
+ mount.handleHit();
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void handleRiderHits(CustomDamageEvent event)
+ {
+ if (event.GetDamageePlayer() == null || event.GetDamageePlayer().getVehicle() == null || !(event.GetDamageePlayer().getVehicle() instanceof Horse))
+ {
+ return;
+ }
+ if (event.GetDamagerPlayer(true) != null && event.GetDamagerPlayer(true).getEntityId() == event.GetDamageePlayer().getEntityId())
+ {
+ return;
+ }
+ Mount mount = _spawnedMounts.get(event.GetDamageePlayer().getVehicle());
+ if (mount == null)
+ {
+ return;
+ }
+ if (event.GetCause() != DamageCause.FALL)
+ {
+ mount.handleHit();
+ }
+ }
+
+ @EventHandler
+ public void onEditHorseInventory(InventoryClickEvent event)
+ {
+ if (!(event.getClickedInventory() instanceof HorseInventory))
+ {
+ return;
+ }
+ if (!_spawnedMounts.containsKey(event.getClickedInventory().getHolder()))
+ {
+ return;
+ }
+ if (event.getSlot() == 0 || event.getSlot() == 1)
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void mountInteract(PlayerInteractEntityEvent event)
+ {
+ if (!(event.getRightClicked() instanceof Horse))
+ {
+ return;
+ }
+ Mount mount = _spawnedMounts.get(event.getRightClicked());
+ if (mount == null)
+ {
+ return;
+ }
+ if (mount.getOwner().getEntityId() == event.getPlayer().getEntityId())
+ {
+ return;
+ }
+
+ UtilPlayer.message(event.getPlayer(), F.main(getName(), "This is not your Mount!"));
+ event.setCancelled(true);
+ }
+
+ @Override
+ public String getQuery(int accountId, String uuid, String name)
+ {
+ return "SELECT am.id, am.mountTypeId, am.mountSkinId, ms.statToken FROM accountClansMounts AS am INNER JOIN clansMountStats AS ms ON ms.mountId = am.id WHERE am.accountId=" + accountId + ";";
+ }
+
+ @Override
+ public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
+ {
+ MountOwnerData data = new MountOwnerData();
+ while (resultSet.next())
+ {
+ MountToken token = new MountToken();
+ token.Id = resultSet.getInt("id");
+ token.Type = MountType.getFromId(resultSet.getInt("mountTypeId"));
+ token.Skin = SkinType.getFromId(resultSet.getInt("mountSkinId"));
+ MountStatToken statToken = Utility.deserialize(resultSet.getString("statToken"), MountStatToken.class);
+ data.acceptLoad(token, statToken);
+ }
+ Set(uuid, data);
+ }
+
+ @Override
+ protected MountOwnerData addPlayer(UUID uuid)
+ {
+ return new MountOwnerData();
+ }
+
+ public static double getSpeed(int stars)
+ {
+ stars = Math.min(Math.max(1, stars), 3);
+ return SPEED_STARS[stars - 1];
+ }
+
+ public static double getJump(int stars)
+ {
+ stars = Math.min(Math.max(1, stars), 3);
+ return JUMP_STARS[stars - 1];
+ }
+
+ public static int getStrength(int stars)
+ {
+ stars = Math.min(Math.max(1, stars), 3);
+ return STRENGTH_STARS[stars - 1];
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountOwnerData.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountOwnerData.java
new file mode 100644
index 000000000..9fdf52455
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountOwnerData.java
@@ -0,0 +1,80 @@
+package mineplex.game.clans.clans.mounts;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import mineplex.core.common.Pair;
+import mineplex.core.common.util.UtilMath;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+
+public class MountOwnerData
+{
+ private Map _mounts = new LinkedHashMap<>();
+
+ public List> getOwnedMounts(boolean onlyInitialized)
+ {
+ return _mounts.entrySet().stream().filter(entry -> onlyInitialized ? entry.getKey().Id != -1 : true).map(entry -> Pair.create(entry.getKey(), entry.getValue())).collect(Collectors.toList());
+ }
+
+ public List> getOwnedMounts(boolean onlyInitialized, MountType type)
+ {
+ return _mounts.entrySet().stream().filter(entry -> (onlyInitialized ? entry.getKey().Id != -1 : true) && type == entry.getKey().Type).map(entry -> Pair.create(entry.getKey(), entry.getValue())).collect(Collectors.toList());
+ }
+
+ public MountStatToken getStatToken(MountToken mountToken)
+ {
+ return _mounts.get(mountToken);
+ }
+
+ public boolean ownsMount(MountType type)
+ {
+ return getAmountOwned(type) > 0;
+ }
+
+ public long getAmountOwned(MountType type)
+ {
+ return _mounts.keySet().stream().filter(token -> token.Type == type).count();
+ }
+
+ public void acceptLoad(MountToken token, MountStatToken statToken)
+ {
+ _mounts.put(token, statToken);
+ }
+
+ public Pair grantMount(MountType type, int speed, int jump, int strength)
+ {
+ MountToken token = new MountToken();
+ token.Type = type;
+ MountStatToken statToken = new MountStatToken();
+ statToken.JumpStars = jump;
+ statToken.SpeedStars = speed;
+ statToken.StrengthStars = strength;
+ _mounts.put(token, statToken);
+
+ return Pair.create(token, statToken);
+ }
+
+ public Pair grantMount(MountType type)
+ {
+ int speed = UtilMath.rRange(1, 3);
+ int jump = UtilMath.rRange(1, 3);
+ int strength = UtilMath.rRange(1, 3);
+
+ return grantMount(type, speed, jump, strength);
+ }
+
+ public Integer[] removeMounts(MountType type)
+ {
+ Integer[] array = _mounts.keySet().stream().filter(token->token.Type == type).map(token->token.Id).toArray(size->new Integer[size]);
+ _mounts.keySet().removeIf(token->token.Type == type);
+
+ return array;
+ }
+
+ public void removeMount(int id)
+ {
+ _mounts.keySet().removeIf(token->token.Id == id);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountRepository.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountRepository.java
new file mode 100644
index 000000000..821c887d2
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountRepository.java
@@ -0,0 +1,180 @@
+package mineplex.game.clans.clans.mounts;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.bukkit.plugin.java.JavaPlugin;
+
+import mineplex.core.common.Pair;
+import mineplex.serverdata.Utility;
+import mineplex.serverdata.database.DBPool;
+import mineplex.serverdata.database.RepositoryBase;
+import mineplex.serverdata.database.column.ColumnInt;
+import mineplex.serverdata.database.column.ColumnVarChar;
+
+/**
+ * Database repository class for mounts
+ */
+public class MountRepository extends RepositoryBase
+{
+ private static final String CREATE_MOUNTS_TABLE = "CREATE TABLE IF NOT EXISTS accountClansMounts (id INT NOT NULL AUTO_INCREMENT,"
+ + "accountId INT NOT NULL,"
+ + "mountTypeId INT NOT NULL,"
+ + "mountSkinId INT NOT NULL,"
+ + "INDEX typeIndex (mountTypeId),"
+ + "INDEX skinIndex (mountSkinId),"
+ + "PRIMARY KEY (id));";
+
+ private static final String CREATE_MOUNT_STATS_TABLE = "CREATE TABLE IF NOT EXISTS clansMountStats (mountId INT NOT NULL,"
+ + "statToken VARCHAR(20) NOT NULL,"
+ + "PRIMARY KEY (mountId));";
+
+ private static final String INSERT_MOUNT = "INSERT INTO accountClansMounts (accountId, mountTypeId, mountSkinId) VALUES (?, ?, ?);";
+ private static final String SAVE_MOUNT = "UPDATE accountClansMounts SET mountSkinId=? WHERE id=?;";
+ private static final String SAVE_MOUNT_STATS = "INSERT INTO clansMountStats (mountId, statToken) VALUES (?, ?) ON DUPLICATE KEY UPDATE statToken=VALUES(statToken);";
+ private static final String DELETE_MOUNT = "DELETE FROM accountClansMounts WHERE id=?;";
+ private static final String DELETE_MOUNT_STATS = "DELETE FROM clansMountStats WHERE mountId=?;";
+
+ private MountManager _mountManager;
+
+ public MountRepository(JavaPlugin plugin, MountManager mountManager)
+ {
+ super(DBPool.getAccount());
+ _mountManager = mountManager;
+ }
+
+ /**
+ * Saves a mount into the database
+ * @param accountId The owner's account id
+ * @param token The mount token to save
+ * @param statToken The stat token to save
+ */
+ public void saveMount(final int accountId, final MountToken token, final MountStatToken statToken)
+ {
+ _mountManager.runAsync(() ->
+ {
+ try (Connection connection = getConnection();)
+ {
+ if (token.Id == -1)
+ {
+ executeInsert(connection, INSERT_MOUNT, idResult ->
+ {
+ if (idResult.next())
+ {
+ token.Id = idResult.getInt(1);
+ }
+ }, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin == null ? -1 : token.Skin.getId()));
+ }
+ else
+ {
+ executeUpdate(connection, SAVE_MOUNT, null, new ColumnInt("mountSkinId", token.Skin == null ? -1 : token.Skin.getId()), new ColumnInt("id", token.Id));
+ }
+ if (token.Id == -1)
+ {
+ return;
+ }
+ executeUpdate(connection, SAVE_MOUNT_STATS, null, new ColumnInt("mountId", token.Id), new ColumnVarChar("statToken", 20, Utility.serialize(statToken)));
+ }
+ catch (SQLException e)
+ {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * Saves a list of mounts into the database
+ * @param accountId The owner's account id
+ * @param tokens The list of token pairs to save
+ */
+ public void saveMounts(final int accountId, final List> tokens)
+ {
+ _mountManager.runAsync(() ->
+ {
+ try (Connection connection = getConnection())
+ {
+ for (Pair tokenPair : tokens)
+ {
+ MountToken token = tokenPair.getLeft();
+ MountStatToken statToken = tokenPair.getRight();
+
+ if (token.Id == -1)
+ {
+ executeInsert(connection, INSERT_MOUNT, idResult ->
+ {
+ if (idResult.next())
+ {
+ token.Id = idResult.getInt(1);
+ }
+ }, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin == null ? -1 : token.Skin.getId()));
+ }
+ else
+ {
+ executeUpdate(connection, SAVE_MOUNT, null, new ColumnInt("mountSkinId", token.Skin == null ? -1 : token.Skin.getId()), new ColumnInt("id", token.Id));
+ }
+ if (token.Id == -1)
+ {
+ continue;
+ }
+ executeUpdate(connection, SAVE_MOUNT_STATS, null, new ColumnInt("mountId", token.Id), new ColumnVarChar("statToken", 100, Utility.serialize(statToken)));
+ }
+ }
+ catch (SQLException e)
+ {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * Deletes a mount from the database
+ * @param token The mount to delete
+ */
+ public void deleteMount(final MountToken token, final Consumer after)
+ {
+ if (token.Id == -1)
+ {
+ return;
+ }
+ _mountManager.runAsync(() ->
+ {
+ executeUpdate(DELETE_MOUNT, new ColumnInt("id", token.Id));
+ executeUpdate(DELETE_MOUNT_STATS, new ColumnInt("mountId", token.Id));
+ if (after != null)
+ {
+ _mountManager.runSync(() ->
+ {
+ after.accept(token.Id);
+ });
+ }
+ });
+ }
+
+ /**
+ * Deletes an array from the database
+ * @param ids The mount ids to delete
+ */
+ public void deleteMounts(final int[] ids, final Runnable after)
+ {
+ if (ids.length <= 0)
+ {
+ return;
+ }
+ _mountManager.runAsync(() ->
+ {
+ String idList = ids[0] + "";
+ for (int i = 1; i < ids.length; i++)
+ {
+ idList += ("," + ids[i]);
+ }
+ executeUpdate(DELETE_MOUNT.replace("id=?;", "id IN (" + idList + ");"));
+ executeUpdate(DELETE_MOUNT_STATS.replace("mountId=?;", "mountId IN (" + idList + ");"));
+ if (after != null)
+ {
+ _mountManager.runSync(after);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountSpawnEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountSpawnEvent.java
new file mode 100644
index 000000000..9d3e788aa
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountSpawnEvent.java
@@ -0,0 +1,34 @@
+package mineplex.game.clans.clans.mounts;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+/**
+ * Event called after a mount spawns
+ */
+public class MountSpawnEvent extends Event
+{
+ private static final HandlerList handlers = new HandlerList();
+
+ private final Mount _mount;
+
+ public MountSpawnEvent(Mount mount)
+ {
+ _mount = mount;
+ }
+
+ public Mount getMount()
+ {
+ return _mount;
+ }
+
+ public HandlerList getHandlers()
+ {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList()
+ {
+ return handlers;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountStatToken.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountStatToken.java
new file mode 100644
index 000000000..42517042e
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountStatToken.java
@@ -0,0 +1,8 @@
+package mineplex.game.clans.clans.mounts;
+
+public class MountStatToken
+{
+ public int JumpStars = 1;
+ public int SpeedStars = 1;
+ public int StrengthStars = 1;
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountToken.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountToken.java
new file mode 100644
index 000000000..8940344c0
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/MountToken.java
@@ -0,0 +1,11 @@
+package mineplex.game.clans.clans.mounts;
+
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+import mineplex.game.clans.clans.mounts.Mount.SkinType;
+
+public class MountToken
+{
+ public int Id = -1;
+ public MountType Type = null;
+ public SkinType Skin = null;
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountOverviewPage.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountOverviewPage.java
new file mode 100644
index 000000000..e3e1021ca
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountOverviewPage.java
@@ -0,0 +1,166 @@
+package mineplex.game.clans.clans.mounts.gui;
+
+import java.util.List;
+
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.ClickType;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import mineplex.core.common.Pair;
+import mineplex.core.common.util.C;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.core.shop.confirmation.ConfirmationCallback;
+import mineplex.core.shop.confirmation.ConfirmationPage;
+import mineplex.core.shop.confirmation.ConfirmationProcessor;
+import mineplex.core.shop.item.IButton;
+import mineplex.core.shop.page.ShopPageBase;
+import mineplex.game.clans.clans.mounts.Mount.MountType;
+import mineplex.game.clans.clans.mounts.MountManager;
+import mineplex.game.clans.clans.mounts.MountStatToken;
+import mineplex.game.clans.clans.mounts.MountToken;
+
+public class MountOverviewPage extends ShopPageBase
+{
+ private final String STAR = "✩";
+
+ public MountOverviewPage(MountManager plugin, MountShop shop, String name, Player player)
+ {
+ super(plugin, shop, plugin.getClientManager(), plugin.getDonationManager(), name, player, 27);
+
+ buildPage();
+ }
+
+ private ItemStack toItem(MountToken mountToken, MountStatToken statToken, boolean overview)
+ {
+ ItemBuilder builder = new ItemBuilder(mountToken.Type.getDisplayType());
+ builder.setTitle(mountToken.Type.getDisplayName() + " Mount");
+ builder.addLore(C.cPurple + "Skin: " + (mountToken.Skin == null ? C.cYellow + "Default" : mountToken.Skin.getDisplayName()));
+ String strength = C.cYellow;
+ for (int i = 0; i < statToken.StrengthStars; i++)
+ {
+ strength += STAR;
+ }
+ builder.addLore(C.cPurple + "Strength: " + strength);
+ String speed = C.cYellow;
+ for (int i = 0; i < statToken.SpeedStars; i++)
+ {
+ speed += STAR;
+ }
+ builder.addLore(C.cPurple + "Speed: " + speed);
+ String jump = C.cYellow;
+ for (int i = 0; i < statToken.JumpStars; i++)
+ {
+ jump += STAR;
+ }
+ builder.addLore(C.cPurple + "Jump: " + jump);
+ if (overview)
+ {
+ builder.addLore(C.cRed);
+ builder.addLore(C.cDGreen + "Left-Click to Summon");
+ builder.addLore(C.cDGreen + "Right-Click to Manage Skin");
+ builder.addLore(C.cDRed + "Shift Right-Click to Destroy");
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ protected void buildPage()
+ {
+ int[] horseSlots = {10, 11, 12};
+ List> horses = getPlugin().Get(getPlayer()).getOwnedMounts(true, MountType.HORSE);
+ int[] donkeySlots = {14, 15, 16};
+ List> donkeys = getPlugin().Get(getPlayer()).getOwnedMounts(true, MountType.DONKEY);
+
+ for (int i = 0; i < horseSlots.length; i++)
+ {
+ int slot = horseSlots[i];
+ ItemStack item = new ItemBuilder(Material.INK_SACK).setData((short)8).setTitle(C.cRed).build();
+ IButton button = null;
+ if (horses.size() > i)
+ {
+ Pair tokens = horses.get(i);
+ item = toItem(tokens.getLeft(), tokens.getRight(), true);
+ button = (player, clickType) ->
+ {
+ if (clickType == ClickType.LEFT)
+ {
+ if (!getPlugin().summonMount(player, tokens.getLeft()))
+ {
+ playDenySound(player);
+ }
+ }
+ else if (clickType == ClickType.RIGHT)
+ {
+ getShop().openPageForPlayer(player, new MountSkinPage(this, player, tokens.getLeft()));
+ }
+ else if (clickType == ClickType.SHIFT_RIGHT)
+ {
+ getShop().openPageForPlayer(player, new ConfirmationPage(player, MountOverviewPage.this, new ConfirmationProcessor()
+ {
+ @Override
+ public void init(Inventory inventory) {}
+
+ @Override
+ public void process(ConfirmationCallback callback)
+ {
+ getPlugin().removeMountToken(player, tokens.getLeft(), () ->
+ {
+ MountOverviewPage.this.refresh();
+ callback.resolve("Mount successfully deleted!");
+ });
+ }
+ }, toItem(tokens.getLeft(), tokens.getRight(), false)));
+ }
+ };
+ }
+ addButton(slot, item, button);
+ }
+ for (int i = 0; i < donkeySlots.length; i++)
+ {
+ int slot = donkeySlots[i];
+ ItemStack item = new ItemBuilder(Material.INK_SACK).setData((short)8).setTitle(C.cRed).build();
+ IButton button = null;
+ if (donkeys.size() > i)
+ {
+ Pair tokens = donkeys.get(i);
+ item = toItem(tokens.getLeft(), tokens.getRight(), true);
+ button = (player, clickType) ->
+ {
+ if (clickType == ClickType.LEFT)
+ {
+ if (!getPlugin().summonMount(player, tokens.getLeft()))
+ {
+ playDenySound(player);
+ }
+ }
+ else if (clickType == ClickType.RIGHT)
+ {
+ getShop().openPageForPlayer(player, new MountSkinPage(this, player, tokens.getLeft()));
+ }
+ else if (clickType == ClickType.SHIFT_RIGHT)
+ {
+ getShop().openPageForPlayer(player, new ConfirmationPage(player, new MountOverviewPage(getPlugin(), getShop(), getName(), getPlayer()), new ConfirmationProcessor()
+ {
+ @Override
+ public void init(Inventory inventory) {}
+
+ @Override
+ public void process(ConfirmationCallback callback)
+ {
+ getPlugin().removeMountToken(player, tokens.getLeft(), () ->
+ {
+ MountOverviewPage.this.refresh();
+ callback.resolve("Mount successfully deleted!");
+ });
+ }
+ }, toItem(tokens.getLeft(), tokens.getRight(), false)));
+ }
+ };
+ }
+ addButton(slot, item, button);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountShop.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountShop.java
new file mode 100644
index 000000000..d6dd454d5
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountShop.java
@@ -0,0 +1,21 @@
+package mineplex.game.clans.clans.mounts.gui;
+
+import org.bukkit.entity.Player;
+
+import mineplex.core.shop.ShopBase;
+import mineplex.core.shop.page.ShopPageBase;
+import mineplex.game.clans.clans.mounts.MountManager;
+
+public class MountShop extends ShopBase
+{
+ public MountShop(MountManager plugin)
+ {
+ super(plugin, plugin.getClientManager(), plugin.getDonationManager(), "Manage Mounts");
+ }
+
+ @Override
+ protected ShopPageBase> buildPagesFor(Player player)
+ {
+ return new MountOverviewPage(getPlugin(), this, "Manage Mounts", player);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountSkinPage.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountSkinPage.java
new file mode 100644
index 000000000..64498e6c1
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/mounts/gui/MountSkinPage.java
@@ -0,0 +1,142 @@
+package mineplex.game.clans.clans.mounts.gui;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import mineplex.core.common.Rank;
+import mineplex.core.common.util.C;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.core.shop.page.ShopPageBase;
+import mineplex.game.clans.clans.mounts.Mount.SkinType;
+import mineplex.game.clans.clans.mounts.MountManager;
+import mineplex.game.clans.clans.mounts.MountToken;
+
+public class MountSkinPage extends ShopPageBase
+{
+ private MountOverviewPage _overview;
+ private MountToken _token;
+
+ public MountSkinPage(MountOverviewPage overview, Player player, MountToken token)
+ {
+ super(overview.getPlugin(), overview.getShop(), overview.getClientManager(), overview.getDonationManager(), "Skin Management", player, 54);
+
+ _overview = overview;
+ _token = token;
+ buildPage();
+ }
+
+ private List getAllowed()
+ {
+ List allowed = new LinkedList<>();
+
+ for (SkinType type : SkinType.values())
+ {
+ if (Arrays.asList(type.getPossibleTypes()).contains(_token.Type))
+ {
+ allowed.add(type);
+ }
+ }
+
+ return allowed;
+ }
+
+ private boolean hasUnlocked(Player player, SkinType type)
+ {
+ if (getClientManager().Get(player).GetRank().has(Rank.ADMIN))
+ {
+ return true;
+ }
+
+ return getDonationManager().Get(player).ownsUnknownSalesPackage(type.getPackageName());
+ }
+
+ private boolean hasUnlocked(SkinType type)
+ {
+ return hasUnlocked(getPlayer(), type);
+ }
+
+ private ItemStack buildResetItem()
+ {
+ ItemBuilder builder = new ItemBuilder(Material.WATER_BUCKET);
+
+ builder.setTitle(C.cYellow + "Default Skin");
+ if (_token.Skin == null)
+ {
+ builder.setLore(C.cRed, C.cGreenB + "SELECTED");
+ }
+
+ return builder.build();
+ }
+
+ private ItemStack buildSkinItem(SkinType type)
+ {
+ ItemBuilder builder = new ItemBuilder(type.getBaseDisplay());
+
+ builder.setTitle(type.getDisplayName());
+ builder.setLore(C.cRed);
+ if (_token.Skin == type)
+ {
+ builder.addLore(C.cGreenB + "SELECTED");
+ }
+ else if (hasUnlocked(type))
+ {
+ builder.addLore(C.cGreenB + "UNLOCKED");
+ }
+ else
+ {
+ builder.addLore(C.cGray + "Available at http://www.mineplex.com/shop");
+ builder.addLore(C.cRedB + "LOCKED");
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ protected void buildPage()
+ {
+ addButton(0, new ItemBuilder(Material.BED).setTitle(C.cGreen + "Back").build(), (player, clickType) ->
+ {
+ _overview.refresh();
+ getShop().openPageForPlayer(player, _overview);
+ });
+ addButton(13, buildResetItem(), (player, clickType) ->
+ {
+ if (_token.Skin == null)
+ {
+ playDenySound(player);
+ }
+ else
+ {
+ playAcceptSound(player);
+ _token.Skin = null;
+ getPlugin().getRepository().saveMount(getClientManager().Get(player).getAccountId(), _token, getPlugin().Get(player).getStatToken(_token));
+ refresh();
+ }
+ });
+ int[] skinSlots = {20, 21, 22, 23, 24, 29, 30, 31, 32, 33, 38, 39, 40, 41, 42};
+ List allowed = getAllowed();
+ for (int i = 0; i < skinSlots.length && i < allowed.size(); i++)
+ {
+ SkinType type = allowed.get(i);
+ addButton(skinSlots[i], buildSkinItem(type), (player, clickType) ->
+ {
+ if (hasUnlocked(player, type) && _token.Skin != type)
+ {
+ playAcceptSound(player);
+ _token.Skin = type;
+ getPlugin().getRepository().saveMount(getClientManager().Get(player).getAccountId(), _token, getPlugin().Get(player).getStatToken(_token));
+ refresh();
+ }
+ else
+ {
+ playDenySound(player);
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/NetherManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/NetherManager.java
index 79f0dab91..bca2c1acc 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/NetherManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/NetherManager.java
@@ -1,5 +1,6 @@
package mineplex.game.clans.clans.nether;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -19,6 +20,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
@@ -52,11 +54,8 @@ import mineplex.game.clans.clans.nether.command.ForceTeleportCommand;
import mineplex.game.clans.clans.nether.command.PortalCommand;
import mineplex.game.clans.clans.nether.data.ClaimData;
import mineplex.game.clans.clans.nether.miniboss.NetherMinibossManager;
+import mineplex.game.clans.clans.worldevent.boss.BossDeathEvent;
import mineplex.game.clans.spawn.Spawn;
-import mineplex.minecraft.game.core.boss.EventCreatureDeathEvent;
-import mineplex.minecraft.game.core.boss.broodmother.SpiderCreature;
-import mineplex.minecraft.game.core.boss.ironwizard.GolemCreature;
-import mineplex.minecraft.game.core.boss.skeletonking.SkeletonCreature;
/**
* Manager for all nether features
@@ -75,9 +74,9 @@ public class NetherManager extends MiniPlugin
private PortalRepository _repo;
private NetherMinibossManager _miniboss;
private World _netherWorld;
- private List _portals = Lists.newArrayList();
- public List BossPortals = Lists.newArrayList();
- private List _returnPortals = Lists.newArrayList();
+ private List _portals = new ArrayList<>();
+ public List BossPortals = new ArrayList<>();
+ private List _returnPortals = new ArrayList<>();
public Map InNether = new HashMap<>();
public Map OverworldOrigins = new HashMap<>();
public Map Claiming = new HashMap<>();
@@ -151,7 +150,17 @@ public class NetherManager extends MiniPlugin
*/
public boolean isInNether(Player player)
{
- return player.getWorld().equals(_netherWorld);
+ return isInNether(player.getLocation());
+ }
+
+ /**
+ * Checks if a location is in the nether
+ * @param location The location to check
+ * @return Whether the player is in the nether
+ */
+ public boolean isInNether(Location location)
+ {
+ return location.getWorld().equals(_netherWorld);
}
/**
@@ -298,6 +307,7 @@ public class NetherManager extends MiniPlugin
}
BossNetherPortal portal = new BossNetherPortal(bossSpawn.clone().add(-2, 5, 0), bossSpawn.clone().add(2, 0, 0), false);
portal.open(PORTAL_OPEN_DURATION);
+ BossPortals.add(portal);
for (NetherPortal returnPortal : _returnPortals)
{
returnPortal.open(-1);
@@ -493,13 +503,19 @@ public class NetherManager extends MiniPlugin
@EventHandler
public void onTpHome(ClansCommandExecutedEvent event)
{
+ if (!isInNether(event.getPlayer()))
+ {
+ return;
+ }
if (event.getCommand().equalsIgnoreCase("tphome") || event.getCommand().equalsIgnoreCase("stuck"))
{
- if (isInNether(event.getPlayer()))
- {
- event.setCancelled(true);
- UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot teleport while in " + F.clansNether("The Nether") + "!"));
- }
+ event.setCancelled(true);
+ UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot teleport while in " + F.clansNether("The Nether") + "!"));
+ }
+ if (event.getCommand().equalsIgnoreCase("claim") || event.getCommand().equalsIgnoreCase("unclaim") || event.getCommand().equalsIgnoreCase("unclaimall") || event.getCommand().equalsIgnoreCase("homeset"))
+ {
+ event.setCancelled(true);
+ UtilPlayer.message(event.getPlayer(), F.main(getName(), "You cannot manage your clan's territory while in " + F.clansNether("The Nether") + "!"));
}
}
@@ -555,11 +571,17 @@ public class NetherManager extends MiniPlugin
}
@EventHandler
- public void onBossDeath(EventCreatureDeathEvent event)
+ public void onBossDeath(BossDeathEvent event)
{
- if (event.getCreature() instanceof GolemCreature || event.getCreature() instanceof SkeletonCreature || event.getCreature() instanceof SpiderCreature)
+ spawnBossPortal(event.getEvent().getCenterLocation().clone());
+ }
+
+ @EventHandler
+ public void onBlockDamage(EntityExplodeEvent event)
+ {
+ if (isInNether(event.getLocation()))
{
- spawnBossPortal(event.getCreature().getEvent().getCenterLocation().clone().subtract(0, 1, 0));
+ event.setYield(0f);
}
}
}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/MinibossFireball.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/MinibossFireball.java
index d33ad0de6..ea2976684 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/MinibossFireball.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/MinibossFireball.java
@@ -1,11 +1,6 @@
package mineplex.game.clans.clans.nether.miniboss;
-import java.util.HashMap;
-
-import mineplex.core.common.util.UtilAction;
-import mineplex.core.common.util.UtilAlg;
-import mineplex.core.common.util.UtilEnt;
-import mineplex.game.clans.clans.ClansManager;
+import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
@@ -18,6 +13,11 @@ import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.util.Vector;
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilAlg;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.game.clans.clans.ClansManager;
+
/**
* Manager class for managing boss fireballs
*/
@@ -48,7 +48,7 @@ public class MinibossFireball implements Listener
return;
}
- HashMap hitMap = UtilEnt.getInRadius(proj.getLocation(), FIREBALL_EXPLOSION_RANGE);
+ Map hitMap = UtilEnt.getInRadius(proj.getLocation(), FIREBALL_EXPLOSION_RANGE);
for (LivingEntity cur : hitMap.keySet())
{
double range = hitMap.get(cur);
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossManager.java
index 3909e69c5..d93b5ba04 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossManager.java
@@ -1,8 +1,8 @@
package mineplex.game.clans.clans.nether.miniboss;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -29,7 +29,7 @@ public class NetherMinibossManager implements Listener
{
private static final long MINIBOSS_SPAWN_RATE = 10000;
private NetherManager _manager;
- private HashMap _spawns = new HashMap<>();
+ private Map _spawns = new HashMap<>();
private long _lastSpawned;
private boolean _allowSpawn = false;
private boolean _allowSpawnEvent = false;
@@ -49,16 +49,13 @@ public class NetherMinibossManager implements Listener
sort.add(new Location(manager.getNetherWorld(), 43, 134, 22));
sort.add(new Location(manager.getNetherWorld(), 102, 141, -31));
sort.add(new Location(manager.getNetherWorld(), 151, 136, 34));
- sort.sort(new Comparator()
+ sort.sort((o1, o2) ->
{
- public int compare(Location o1, Location o2)
+ if (UtilMath.offset2d(o1, manager.getNetherWorld().getSpawnLocation()) < UtilMath.offset(o2, manager.getNetherWorld().getSpawnLocation()))
{
- if (UtilMath.offset2d(o1, manager.getNetherWorld().getSpawnLocation()) < UtilMath.offset(o2, manager.getNetherWorld().getSpawnLocation()))
- {
- return -1;
- }
- return 1;
+ return -1;
}
+ return 1;
});
for (int i = 0; i < 3; i++)
{
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossType.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossType.java
index 938810015..3c48b7616 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossType.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/NetherMinibossType.java
@@ -17,12 +17,12 @@ public enum NetherMinibossType
ARCHER("Undead Archer", 25D, EntityType.SKELETON, ArcherMiniboss.class)
;
- private Class extends NetherMiniBoss> _code;
+ private Class extends NetherMiniBoss>> _code;
private String _name;
private Double _maxHealth;
private EntityType _type;
- private NetherMinibossType(String name, Double maxHealth, EntityType type, Class extends NetherMiniBoss> code)
+ private NetherMinibossType(String name, Double maxHealth, EntityType type, Class extends NetherMiniBoss>> code)
{
_name = name;
_maxHealth = maxHealth;
@@ -35,7 +35,7 @@ public enum NetherMinibossType
* @param spawn The location to spawn the boss in
* @return The instance of the miniboss
*/
- public NetherMiniBoss getNewInstance(Location spawn)
+ public NetherMiniBoss> getNewInstance(Location spawn)
{
try
{
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/ArcherMiniboss.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/ArcherMiniboss.java
index d2a4e938c..b280f3393 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/ArcherMiniboss.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/ArcherMiniboss.java
@@ -2,13 +2,6 @@ package mineplex.game.clans.clans.nether.miniboss.bosses;
import java.util.Random;
-import mineplex.core.common.util.UtilMath;
-import mineplex.game.clans.clans.ClansManager;
-import mineplex.game.clans.clans.amplifiers.AmplifierManager;
-import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
-import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
-import mineplex.minecraft.game.core.damage.CustomDamageEvent;
-
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Arrow;
@@ -28,6 +21,13 @@ import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
+import mineplex.core.common.util.UtilMath;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.amplifiers.AmplifierManager;
+import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
+import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+
/**
* Class for running an individual Archer miniboss
*/
@@ -35,7 +35,10 @@ public class ArcherMiniboss extends NetherMiniBoss
{
private static final int BARBED_LEVEL = 1;
private static final double RUNE_DROP_CHANCE = .02;
- private static final int MAX_DIAMOND_DROPS = 5;
+ private static final int MAX_VALUABLE_DROPS = 5;
+ private static final Material[] VALUABLE_DROP_TYPES = new Material[] {Material.DIAMOND, Material.GOLD_INGOT, Material.IRON_INGOT, Material.LEATHER};
+ private static final Material[] SET_DROP_TYPES = new Material[] {Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS, Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS, Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS, Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS};
+ private static final double SET_DROP_CHANCE = .02;
public ArcherMiniboss(String displayName, Double maxHealth, Location spawn, EntityType type)
{
@@ -63,7 +66,7 @@ public class ArcherMiniboss extends NetherMiniBoss
@Override
public void customDeath(Location deathLocation)
{
- deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(Material.DIAMOND, UtilMath.r(MAX_DIAMOND_DROPS) + 1));
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(VALUABLE_DROP_TYPES[UtilMath.r(VALUABLE_DROP_TYPES.length)], UtilMath.r(MAX_VALUABLE_DROPS) + 1));
double runeDropChance = RUNE_DROP_CHANCE;
if (ClansManager.getInstance().getAmplifierManager().hasActiveAmplifier())
{
@@ -74,6 +77,10 @@ public class ArcherMiniboss extends NetherMiniBoss
RuneAttribute runeType = RuneAttribute.values()[UtilMath.r(RuneAttribute.values().length)];
deathLocation.getWorld().dropItemNaturally(deathLocation, ClansManager.getInstance().getGearManager().getRuneManager().getRune(runeType));
}
+ if (new Random().nextDouble() <= SET_DROP_CHANCE)
+ {
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(SET_DROP_TYPES[UtilMath.r(SET_DROP_TYPES.length)], 1));
+ }
}
@EventHandler
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/GhastMiniboss.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/GhastMiniboss.java
index 6ff341b58..d618923f5 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/GhastMiniboss.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/GhastMiniboss.java
@@ -2,16 +2,6 @@ package mineplex.game.clans.clans.nether.miniboss.bosses;
import java.util.Random;
-import mineplex.core.common.util.UtilEnt;
-import mineplex.core.common.util.UtilMath;
-import mineplex.core.common.util.UtilPlayer;
-import mineplex.core.common.util.UtilTime;
-import mineplex.game.clans.clans.ClansManager;
-import mineplex.game.clans.clans.amplifiers.AmplifierManager;
-import mineplex.game.clans.clans.nether.miniboss.MinibossFireball;
-import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
-import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
-
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -23,6 +13,16 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.inventory.ItemStack;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilMath;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilTime;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.amplifiers.AmplifierManager;
+import mineplex.game.clans.clans.nether.miniboss.MinibossFireball;
+import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
+import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
+
/**
* Class for running an individual Ghast miniboss
*/
@@ -32,8 +32,11 @@ public class GhastMiniboss extends NetherMiniBoss
private static final long FIREBALL_LAUNCH_RATE = 500;
private static final int FIREBALLS_PER_USE = 5;
private static final double RUNE_DROP_CHANCE = .02;
- private static final int MAX_DIAMOND_DROPS = 5;
+ private static final int MAX_VALUABLE_DROPS = 5;
+ private static final Material[] VALUABLE_DROP_TYPES = new Material[] {Material.DIAMOND, Material.GOLD_INGOT, Material.IRON_INGOT, Material.LEATHER};
private static final double MAX_TARGET_RANGE = 25;
+ private static final Material[] SET_DROP_TYPES = new Material[] {Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS, Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS, Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS, Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS};
+ private static final double SET_DROP_CHANCE = .02;
private long _lastFireballUse;
private int _fireballsRemaining;
@@ -72,7 +75,7 @@ public class GhastMiniboss extends NetherMiniBoss
@Override
public void customDeath(Location deathLocation)
{
- deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(Material.DIAMOND, UtilMath.r(MAX_DIAMOND_DROPS) + 1));
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(VALUABLE_DROP_TYPES[UtilMath.r(VALUABLE_DROP_TYPES.length)], UtilMath.r(MAX_VALUABLE_DROPS) + 1));
double runeDropChance = RUNE_DROP_CHANCE;
if (ClansManager.getInstance().getAmplifierManager().hasActiveAmplifier())
{
@@ -83,6 +86,10 @@ public class GhastMiniboss extends NetherMiniBoss
RuneAttribute runeType = RuneAttribute.values()[UtilMath.r(RuneAttribute.values().length)];
deathLocation.getWorld().dropItemNaturally(deathLocation, ClansManager.getInstance().getGearManager().getRuneManager().getRune(runeType));
}
+ if (new Random().nextDouble() <= SET_DROP_CHANCE)
+ {
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(SET_DROP_TYPES[UtilMath.r(SET_DROP_TYPES.length)], 1));
+ }
}
@Override
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/WarriorMiniboss.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/WarriorMiniboss.java
index 248c9bf64..d978515d6 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/WarriorMiniboss.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/nether/miniboss/bosses/WarriorMiniboss.java
@@ -2,15 +2,6 @@ package mineplex.game.clans.clans.nether.miniboss.bosses;
import java.util.Random;
-import mineplex.core.common.util.UtilAction;
-import mineplex.core.common.util.UtilAlg;
-import mineplex.core.common.util.UtilMath;
-import mineplex.game.clans.clans.ClansManager;
-import mineplex.game.clans.clans.amplifiers.AmplifierManager;
-import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
-import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
-import mineplex.minecraft.game.core.damage.CustomDamageEvent;
-
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
@@ -27,13 +18,25 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilAlg;
+import mineplex.core.common.util.UtilMath;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.amplifiers.AmplifierManager;
+import mineplex.game.clans.clans.nether.miniboss.NetherMiniBoss;
+import mineplex.game.clans.items.runes.RuneManager.RuneAttribute;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+
/**
* Class for running an individual Warrior miniboss
*/
public class WarriorMiniboss extends NetherMiniBoss
{
private static final double RUNE_DROP_CHANCE = .02;
- private static final int MAX_DIAMOND_DROPS = 5;
+ private static final int MAX_VALUABLE_DROPS = 5;
+ private static final Material[] VALUABLE_DROP_TYPES = new Material[] {Material.DIAMOND, Material.GOLD_INGOT, Material.IRON_INGOT, Material.LEATHER};
+ private static final Material[] SET_DROP_TYPES = new Material[] {Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS, Material.GOLD_HELMET, Material.GOLD_CHESTPLATE, Material.GOLD_LEGGINGS, Material.GOLD_BOOTS, Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS, Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS};
+ private static final double SET_DROP_CHANCE = .02;
private static final double LEAP_CHANCE = .9;
private static final double LEAP_MIN_DIST = 3;
private static final double LEAP_MAX_DIST = 16;
@@ -66,7 +69,7 @@ public class WarriorMiniboss extends NetherMiniBoss
@Override
public void customDeath(Location deathLocation)
{
- deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(Material.DIAMOND, UtilMath.r(MAX_DIAMOND_DROPS) + 1));
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(VALUABLE_DROP_TYPES[UtilMath.r(VALUABLE_DROP_TYPES.length)], UtilMath.r(MAX_VALUABLE_DROPS) + 1));
double runeDropChance = RUNE_DROP_CHANCE;
if (ClansManager.getInstance().getAmplifierManager().hasActiveAmplifier())
{
@@ -77,6 +80,10 @@ public class WarriorMiniboss extends NetherMiniBoss
RuneAttribute runeType = RuneAttribute.values()[UtilMath.r(RuneAttribute.values().length)];
deathLocation.getWorld().dropItemNaturally(deathLocation, ClansManager.getInstance().getGearManager().getRuneManager().getRune(runeType));
}
+ if (new Random().nextDouble() <= SET_DROP_CHANCE)
+ {
+ deathLocation.getWorld().dropItemNaturally(deathLocation, new ItemStack(SET_DROP_TYPES[UtilMath.r(SET_DROP_TYPES.length)], 1));
+ }
}
@Override
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java
index 55debe953..3ea0964b8 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/regions/ClansRegions.java
@@ -24,7 +24,7 @@ public class ClansRegions extends MiniPlugin
public final static int SHOP_RADIUS = 6; // Radius of shop claim area (measured in chunks)
public final static int FIELDS_RADIUS = 7; // Radius of fields claim area (measured in chunks)
public final static int BORDERLANDS_RADIUS = 85; // Radius of borderlands claim area (measured in chunks)
- public static final int BORDER_RADIUS = 1250;
+ public static final int BORDER_RADIUS = 1280;
private ClansManager _manager;
private World _world;
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/ClansPlayerScoreboard.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/ClansPlayerScoreboard.java
index 29950b8db..5b2f870b6 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/ClansPlayerScoreboard.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/ClansPlayerScoreboard.java
@@ -13,6 +13,7 @@ import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilText;
import mineplex.core.thereallyoldscoreboardapiweshouldremove.PlayerScoreboard;
import mineplex.core.thereallyoldscoreboardapiweshouldremove.ScoreboardManager;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.clans.ClansUtility.ClanRelation;
@@ -112,17 +113,19 @@ public class ClansPlayerScoreboard extends PlayerScoreboard
team.setPrefix(relation.getColor(false).toString());
}
-
- Objective domObjective;
- if ((domObjective = scoreboard.getObjective(DisplaySlot.BELOW_NAME)) == null)
+ if (Clans.HARDCORE)
{
- domObjective = scoreboard.registerNewObjective("war", "dummy");
- domObjective.setDisplayName("War Points");
- domObjective.setDisplaySlot(DisplaySlot.BELOW_NAME);
- }
+ Objective domObjective;
+ if ((domObjective = scoreboard.getObjective(DisplaySlot.BELOW_NAME)) == null)
+ {
+ domObjective = scoreboard.registerNewObjective("war", "dummy");
+ domObjective.setDisplayName("War Points");
+ domObjective.setDisplaySlot(DisplaySlot.BELOW_NAME);
+ }
- if (clanInfo != null)
- domObjective.getScore(otherPlayer.getName()).setScore(ownScore);
+ if (clanInfo != null)
+ domObjective.getScore(otherPlayer.getName()).setScore(ownScore);
+ }
team.addPlayer(otherPlayer);
}
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/elements/ScoreboardElementPlayer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/elements/ScoreboardElementPlayer.java
index b5e11e8a1..75b8ef44d 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/elements/ScoreboardElementPlayer.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/scoreboard/elements/ScoreboardElementPlayer.java
@@ -58,6 +58,11 @@ public class ScoreboardElementPlayer implements ScoreboardElement
}
}
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ regionString = C.cDRed + "Raid World";
+ }
+
output.add(regionString);
return output;
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java
index ab406664c..223266074 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java
@@ -10,8 +10,10 @@ 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.itemstack.ItemStackFactory;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.clans.siege.command.GiveWeaponCommand;
import mineplex.game.clans.clans.siege.outpost.OutpostManager;
@@ -213,10 +215,24 @@ public class SiegeManager extends MiniPlugin
@EventHandler
public void onBlockPlace(BlockPlaceEvent event)
{
+ if (!Clans.HARDCORE)
+ {
+ return;
+ }
if (event.getItemInHand().isSimilar(Cannon.CANNON_ITEM))
{
event.setCancelled(true);
+ int health = ItemStackFactory.Instance.GetLoreVar(event.getPlayer().getItemInHand(), "Health", 0);
+ if (health != 0)
+ {
+ if (trySpawnCannon(event.getPlayer(), event.getBlock().getLocation()))
+ {
+ event.getPlayer().setItemInHand(UtilInv.decrement(event.getPlayer().getItemInHand()));
+ }
+ return;
+ }
+
if (trySpawnCannon(event.getPlayer(), event.getBlock().getLocation()))
{
event.getPlayer().setItemInHand(UtilInv.decrement(event.getPlayer().getItemInHand()));
@@ -236,6 +252,46 @@ public class SiegeManager extends MiniPlugin
// }
}
+ public boolean trySpawnCannon(Player player, Location location, int health)
+ {
+ if (_clansManager.getNetherManager().isInNether(player))
+ {
+ _clansManager.message(player, "You are not allowed to place this in " + F.clansNether("The Nether") + ".");
+
+ return false;
+ }
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ _clansManager.message(player, "You are not allowed to place this in a raid.");
+
+ return false;
+ }
+
+ if (!_clansManager.isInClan(player))
+ {
+ UtilPlayer.message(player, F.main("Clans", "You must be in a Clan to place a Cannon."));
+ return false;
+ }
+
+ if (_clansManager.hasTimer(player))
+ {
+ UtilPlayer.message(player, F.main("Clans", "You cannot place a Cannon whilst protected from pvp."));
+ return false;
+ }
+
+ ClanTerritory claim = _clansManager.getClanUtility().getClaim(location);
+
+ if (claim != null && !claim.Owner.equals(_clansManager.getClan(player).getName()))
+ {
+ UtilPlayer.message(player, F.main("Clans", "You must place a Cannon in the Wilderness or your own Territory."));
+ return false;
+ }
+
+ spawnCannon(player, location).setHealth(health);
+
+ return true;
+ }
+
public boolean trySpawnCannon(Player player, Location location)
{
if (_clansManager.getNetherManager().isInNether(player))
@@ -244,6 +300,12 @@ public class SiegeManager extends MiniPlugin
return false;
}
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ _clansManager.message(player, "You are not allowed to place this in a raid.");
+
+ return false;
+ }
if (!_clansManager.isInClan(player))
{
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/Outpost.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/Outpost.java
index 09ed9dcbc..c20834e30 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/Outpost.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/Outpost.java
@@ -8,6 +8,7 @@ import java.util.List;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
+import org.bukkit.block.Block;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -63,11 +64,13 @@ import net.minecraft.server.v1_8_R3.AxisAlignedBB;
public class Outpost implements Listener
{
- protected static final long MAX_LIFETIME = 30 * 60 * 1000; // 30 minutes
+ protected static final long MAX_LIFETIME = 45 * 60 * 1000; // 30 minutes
public static final ItemStack OUTPOST_ITEM = new ItemBuilder(Material.BEACON, 1).setRawTitle(C.Reset + C.cBlue + "Outpost").build();
public static final long PREP_TIME = 2 * 60 * 1000;
+ private static final int MAX_HEALTH = 100;
+
private OutpostManager _outpostManager;
private final int _uniqueId;
@@ -103,10 +106,18 @@ public class Outpost implements Listener
private Hologram _lifetimeLeft;
+ private int _health;
+
+ private long _lastDamage;
+
+ private long _lastRegen;
+
public Outpost(OutpostManager outpostManager, OutpostToken token)
{
_outpostManager = outpostManager;
+ _health = MAX_HEALTH;
+
_uniqueId = token.UniqueId;
_ownerClan = token.OwnerClan;
@@ -137,7 +148,36 @@ public class Outpost implements Listener
return;
if (clickType == ClickType.LEFT || clickType == ClickType.SHIFT_LEFT)
- kill();
+ {
+ if (_outpostManager.getClansManager().hasTimer(player))
+ {
+ UtilPlayer.message(player, F.main("Clans", "You cannot destroy an Outpost whilst protected from PvP."));
+ return;
+ }
+ if (!UtilTime.elapsed(_lastDamage, 5000))
+ {
+ return;
+ }
+ if (_health <= 2)
+ {
+ UtilPlayer.message(player, F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
+
+ _core.getBlock().setType(Material.AIR);
+
+ _ownerClan.inform("Your Outpost has been destroyed!", null);
+ UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
+
+ if (getState() == OutpostState.AWAITING)
+ cleanup();
+ else
+ kill();
+
+ return;
+ }
+
+ _lastDamage = System.currentTimeMillis();
+ _health -= 2;
+ }
}
});
@@ -149,7 +189,7 @@ public class Outpost implements Listener
_preHologram2.start();
}
- _blocks = _type.createBuildQueue(_origin, _ownerClan.Clans);
+ _blocks = _type.createBuildQueue(_origin, _ownerClan.Clans, _ownerClan);
_state = token.OutpostState;
@@ -165,6 +205,8 @@ public class Outpost implements Listener
{
_outpostManager = outpostManager;
+ _health = MAX_HEALTH;
+
_uniqueId = outpostManager.getSiegeManager().randomId();
_ownerClan = clan;
@@ -210,7 +252,36 @@ public class Outpost implements Listener
return;
if (clickType == ClickType.LEFT || clickType == ClickType.SHIFT_LEFT)
- kill();
+ {
+ if (_outpostManager.getClansManager().hasTimer(player))
+ {
+ UtilPlayer.message(player, F.main("Clans", "You cannot destroy an Outpost whilst protected from PvP."));
+ return;
+ }
+ if (!UtilTime.elapsed(_lastDamage, 5000))
+ {
+ return;
+ }
+ if (_health <= 2)
+ {
+ UtilPlayer.message(player, F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
+
+ _core.getBlock().setType(Material.AIR);
+
+ _ownerClan.inform("Your Outpost has been destroyed!", null);
+ UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
+
+ if (getState() == OutpostState.AWAITING)
+ cleanup();
+ else
+ kill();
+
+ return;
+ }
+
+ _lastDamage = System.currentTimeMillis();
+ _health -= 2;
+ }
}
});
}
@@ -280,6 +351,20 @@ public class Outpost implements Listener
return;
}
+ for (Block block : UtilBlock.getBlocksInRadius(event.getClickedBlock().getLocation(), 5))
+ {
+ if (block.getType() == Material.WATER || block.getType() == Material.STATIONARY_WATER)
+ {
+ UtilPlayer.message(event.getPlayer(), F.main("Clans", "You cannot activate an Outpost that close to water!"));
+ return;
+ }
+ if (block.getType() == Material.LAVA || block.getType() == Material.STATIONARY_LAVA)
+ {
+ UtilPlayer.message(event.getPlayer(), F.main("Clans", "You cannot activate an Outpost that close to lava!"));
+ return;
+ }
+ }
+
_origin.getBlock().setType(Material.AIR);
beginConstruction();
}
@@ -291,26 +376,35 @@ public class Outpost implements Listener
{
if (event.getBlock().getLocation().equals(_core) && getState() == OutpostState.LIVE)
{
-
- if(_outpostManager.getClansManager().hasTimer(event.getPlayer()))
+ event.setCancelled(true);
+ if (_outpostManager.getClansManager().hasTimer(event.getPlayer()))
{
UtilPlayer.message(event.getPlayer(), F.main("Clans", "You cannot destroy an Outpost whilst protected from PvP."));
- event.setCancelled(true);
return;
}
- UtilPlayer.message(event.getPlayer(), F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
+ if (!UtilTime.elapsed(_lastDamage, 5000))
+ {
+ return;
+ }
+ if (_health <= 2)
+ {
+ UtilPlayer.message(event.getPlayer(), F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
+
+ _core.getBlock().setType(Material.AIR);
+
+ _ownerClan.inform("Your Outpost has been destroyed!", null);
+ UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
+
+ if (getState() == OutpostState.AWAITING)
+ cleanup();
+ else
+ kill();
+
+ return;
+ }
- _core.getBlock().setType(Material.AIR);
-
- _ownerClan.inform("Your Outpost has been destroyed!", null);
- UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
-
- if (getState() == OutpostState.AWAITING)
- cleanup();
- else
- kill();
-
- event.setCancelled(true);
+ _lastDamage = System.currentTimeMillis();
+ _health -= 2;
}
}
@@ -329,20 +423,35 @@ public class Outpost implements Listener
if (event.getBlock().getLocation().equals(_core) && getState() == OutpostState.LIVE)
{
- UtilPlayer.message(event.getPlayer(), F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
-
- _core.getBlock().setType(Material.AIR);
-
- _ownerClan.inform("Your Outpost has been destroyed!", null);
- UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
-
- if (getState() == OutpostState.AWAITING)
- cleanup();
- else
- kill();
-
event.setCancelled(true);
- return;
+ if (_outpostManager.getClansManager().hasTimer(event.getPlayer()))
+ {
+ UtilPlayer.message(event.getPlayer(), F.main("Clans", "You cannot destroy an Outpost whilst protected from PvP."));
+ return;
+ }
+ if (!UtilTime.elapsed(_lastDamage, 5000))
+ {
+ return;
+ }
+ if (_health <= 2)
+ {
+ UtilPlayer.message(event.getPlayer(), F.main("Clans", "You have destroyed " + F.elem(_ownerClan.getName()) + "'s Outpost!"));
+
+ _core.getBlock().setType(Material.AIR);
+
+ _ownerClan.inform("Your Outpost has been destroyed!", null);
+ UtilTextMiddle.display("Siege", "Your Outpost has been destroyed", 20, 100, 20, _ownerClan.getOnlinePlayersArray());
+
+ if (getState() == OutpostState.AWAITING)
+ cleanup();
+ else
+ kill();
+
+ return;
+ }
+
+ _lastDamage = System.currentTimeMillis();
+ _health -= 2;
}
if (UtilAlg.inBoundingBox(event.getBlock().getLocation(), _startCorner.clone().subtract(.5, 0, .5), _endCorner))
@@ -410,7 +519,9 @@ public class Outpost implements Listener
}
if (_lifetimeLeft != null)
- _lifetimeLeft.setText("Despawning in " + F.time(UtilTime.MakeStr(MAX_LIFETIME - (System.currentTimeMillis() - _timeSpawned))));
+ {
+ _lifetimeLeft.setText("Health: " + _health, "Despawning in " + F.time(UtilTime.MakeStr(MAX_LIFETIME - (System.currentTimeMillis() - _timeSpawned))));
+ }
if (_state == OutpostState.CONSTRUCTING)
{
@@ -467,6 +578,11 @@ public class Outpost implements Listener
{
kill();
}
+ if (_health < MAX_HEALTH && UtilTime.elapsed(_lastDamage, 15000) && UtilTime.elapsed(_lastRegen, 1000))
+ {
+ _lastRegen = System.currentTimeMillis();
+ _health++;
+ }
}
}
@@ -498,12 +614,13 @@ public class Outpost implements Listener
_lifetimeLeft.start();
_state = OutpostState.CONSTRUCTING;
- _blocks = new LinkedHashMap<>(_buildQueue = _type.createBuildQueue(_origin, _ownerClan.Clans));
+ _blocks = new LinkedHashMap<>(_buildQueue = _type.createBuildQueue(_origin, _ownerClan.Clans, _ownerClan));
_ownerClan.inform("Siege", "Your Outpost is now being constructed.", null);
//Inform nearby Clans
for (int chunkX = -3; chunkX < 3; chunkX++)
+ {
for (int chunkZ = -3; chunkZ < 3; chunkZ++)
{
ClanTerritory territory = _ownerClan.Clans.getClanUtility().getClaim(_origin.getWorld().getChunkAt(_origin.getChunk().getX() + chunkX, _origin.getChunk().getZ() + chunkZ));
@@ -516,6 +633,7 @@ public class Outpost implements Listener
UtilTextMiddle.display("Siege", "A Siege has been declared on your Clan!", 20, 100, 20, clan.getOnlinePlayersArray());
}
}
+ }
}
public void kill()
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java
index 559fc6b4b..c962a829d 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java
@@ -24,6 +24,7 @@ import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.clans.event.PlayerClaimTerritoryEvent;
@@ -61,6 +62,10 @@ public class OutpostManager extends MiniPlugin
@EventHandler(priority = EventPriority.LOWEST)
public void onPlaceBlock(BlockPlaceEvent event)
{
+ if (!Clans.HARDCORE)
+ {
+ return;
+ }
if (event.getItemInHand().isSimilar(Outpost.OUTPOST_ITEM))
if (!spawnOutpost(event.getPlayer(), event.getBlock().getLocation(), OutpostType.MK_III))
event.setCancelled(true);
@@ -75,13 +80,20 @@ public class OutpostManager extends MiniPlugin
return false;
}
+ if (_clansManager.getWorldEvent().getRaidManager().isInRaid(player.getLocation()))
+ {
+ _clansManager.message(player, "You are not allowed to place this in a raid.");
+
+ return false;
+ }
+
if (!_clansManager.isInClan(player))
{
UtilPlayer.message(player, F.main("Clans", "You must be in a Clan to place an Outpost."));
return false;
}
- if(_clansManager.hasTimer(player))
+ if (_clansManager.hasTimer(player))
{
UtilPlayer.message(player, F.main("Clans", "You can't place an Outpost whilst protected from PvP."));
return false;
@@ -123,6 +135,7 @@ public class OutpostManager extends MiniPlugin
}
for (int x = -2; x < 2; x++)
+ {
for (int z = -2; z < 2; z++)
{
Chunk chunk = location.getWorld().getChunkAt(location.getChunk().getX() + x, location.getChunk().getZ() + z);
@@ -138,10 +151,12 @@ public class OutpostManager extends MiniPlugin
}
}
}
+ }
boolean gut = false;
for (int x = -6; x < 6; x++)
+ {
for (int z = -6; z < 6; z++)
{
Chunk chunk = location.getWorld().getChunkAt(location.getChunk().getX() + x, location.getChunk().getZ() + z);
@@ -159,6 +174,7 @@ public class OutpostManager extends MiniPlugin
}
}
}
+ }
/* das ist schlecht */
if (!gut)
@@ -168,7 +184,9 @@ public class OutpostManager extends MiniPlugin
}
for (int x = -type._size; x < type._size; x++)
+ {
for (int y = -1; y < type._ySize; y++)
+ {
for (int z = -type._size; z < type._size; z++)
{
Location loc = location.clone().add(x, y, z);
@@ -179,6 +197,8 @@ public class OutpostManager extends MiniPlugin
return false;
}
}
+ }
+ }
_outposts.put(clan.getName(), new Outpost(this, clan, location, type));
_idToOutpost.put(Integer.valueOf(_outposts.get(clan.getName()).getUniqueId()), _outposts.get(clan.getName()));
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostType.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostType.java
index 134e6b000..c14bc04d5 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostType.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostType.java
@@ -1,27 +1,30 @@
package mineplex.game.clans.clans.siege.outpost;
import java.io.File;
-import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Objects;
-import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.block.banner.Pattern;
import mineplex.core.common.block.schematic.Schematic;
import mineplex.core.common.block.schematic.UtilSchematic;
import mineplex.core.common.util.UtilWorld;
+import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.banners.BannerManager;
+import mineplex.game.clans.clans.banners.BannerPattern;
+import mineplex.game.clans.clans.banners.ClanBanner;
import mineplex.game.clans.clans.siege.outpost.build.OutpostBlock;
import mineplex.game.clans.clans.siege.outpost.build.OutpostBlockBanner;
-import net.minecraft.server.v1_8_R3.NBTTagCompound;
public enum OutpostType
{
MK_I(1, 3, 6) {
- public LinkedHashMap createBuildQueue(Location location, ClansManager clans)
+ public LinkedHashMap createBuildQueue(Location location, ClansManager clans, ClanInfo owner)
{
LinkedHashMap build = new LinkedHashMap<>();
@@ -232,7 +235,7 @@ public enum OutpostType
}
},
MK_II(2, 5, 25) {
- public LinkedHashMap createBuildQueue(Location location, ClansManager clans)
+ public LinkedHashMap createBuildQueue(Location location, ClansManager clans, ClanInfo owner)
{
try
{
@@ -292,7 +295,7 @@ public enum OutpostType
}
},
MK_III(3, 5, 25) {
- public LinkedHashMap createBuildQueue(Location location, ClansManager clans)
+ public LinkedHashMap createBuildQueue(Location location, ClansManager clans, ClanInfo owner)
{
try
{
@@ -300,6 +303,8 @@ public enum OutpostType
File file = new File("schematic" + File.separator + "outpost_mk_III.schematic");
Schematic schematic = UtilSchematic.loadSchematic(file);
+ BannerManager bm = clans.getBannerManager();
+ ClanBanner cb = bm.LoadedBanners.get(owner.getName());
for (int y = 0; y < schematic.getHeight(); y++)
{
@@ -319,10 +324,16 @@ public enum OutpostType
if (Material.getMaterial(schematic.getBlock(x, y, z)).name().contains("BANNER"))
{
- build.put(UtilWorld.locToStr(loc), new OutpostBlockBanner(build, loc, schematic.getBlock(x, y, z), schematic.getData(x, y, z), DyeColor.RED));
+ if (cb == null)
+ {
+ continue;
+ }
+ build.put(UtilWorld.locToStr(loc), new OutpostBlockBanner(build, loc, schematic.getBlock(x, y, z), schematic.getData(x, y, z), cb.getBaseColor(), cb.getPatterns().stream().map(BannerPattern::getBukkitPattern).filter(Objects::nonNull).toArray(size -> new Pattern[size])));
}
else
+ {
build.put(UtilWorld.locToStr(loc), new OutpostBlock(build, loc, schematic.getBlock(x, y, z), schematic.getData(x, y, z)));
+ }
}
}
}
@@ -374,7 +385,7 @@ public enum OutpostType
return _id;
}
- public abstract LinkedHashMap createBuildQueue(Location location, ClansManager clans);
+ public abstract LinkedHashMap createBuildQueue(Location location, ClansManager clans, ClanInfo owner);
public abstract Location getCoreLocation(Location location);
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/tokens/SiegeWeaponToken.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/tokens/SiegeWeaponToken.java
index 638aa800c..274039ed8 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/tokens/SiegeWeaponToken.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/tokens/SiegeWeaponToken.java
@@ -1,8 +1,5 @@
package mineplex.game.clans.clans.siege.repository.tokens;
-import java.util.Map;
-import java.util.UUID;
-
import org.bukkit.Location;
import mineplex.game.clans.clans.ClanInfo;
@@ -15,6 +12,5 @@ public class SiegeWeaponToken
public Location Location;
public int Health;
public int Yaw;
- public long LastFired;
-
-}
+ public long LastFired;
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/Crater.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/Crater.java
index 0b1630995..c8bbf60ca 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/Crater.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/Crater.java
@@ -1,7 +1,7 @@
package mineplex.game.clans.clans.siege.weapon.projectile;
-import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -110,7 +110,7 @@ public class Crater
}
}, 1L);
- HashMap hitMap = UtilEnt.getInRadius(_origin, 3.5);
+ Map hitMap = UtilEnt.getInRadius(_origin, 3.5);
for (LivingEntity hit : hitMap.keySet())
{
ClansManager.getInstance().getDamageManager().NewDamageEvent(hit, _cause, null, DamageCause.ENTITY_EXPLOSION, 7 / hitMap.get(hit), true, true, false, _cause.getName(), "Siege Cannon");
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java
index 75cd73e49..2cfa6e336 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java
@@ -3,20 +3,13 @@ package mineplex.game.clans.clans.siege.weapon.projectile;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
-import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
-import org.bukkit.event.entity.EntityChangeBlockEvent;
-import org.bukkit.event.entity.EntityExplodeEvent;
-import org.bukkit.util.Vector;
-import mineplex.core.common.util.UtilAlg;
import mineplex.core.common.util.UtilBlock;
-import mineplex.core.common.util.UtilItem;
import mineplex.core.common.util.UtilServer;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/WarManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/WarManager.java
index 592c61a42..05011fe57 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/WarManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/WarManager.java
@@ -18,6 +18,7 @@ import mineplex.core.thereallyoldscoreboardapiweshouldremove.ScoreboardManager;
import mineplex.core.thereallyoldscoreboardapiweshouldremove.elements.ScoreboardElement;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClanTips.TipType;
import mineplex.game.clans.clans.ClansManager;
@@ -107,6 +108,10 @@ public class WarManager extends MiniPlugin implements ScoreboardElement
@EventHandler
public void handleDeath(final ClansPlayerDeathEvent event)
{
+ if (!Clans.HARDCORE)
+ {
+ return;
+ }
ClanInfo deathClan = event.getPlayer().getClan();
if (deathClan == null)
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/command/WarPointsCommand.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/command/WarPointsCommand.java
index efe673ca6..e44c0f21c 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/command/WarPointsCommand.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/war/command/WarPointsCommand.java
@@ -7,6 +7,7 @@ import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilTime;
+import mineplex.game.clans.Clans;
import mineplex.game.clans.clans.ClanInfo;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.core.war.ClanWarData;
@@ -22,6 +23,11 @@ public class WarPointsCommand extends CommandBase
@Override
public void Execute(Player caller, String[] args)
{
+ if (!Clans.HARDCORE)
+ {
+ UtilPlayer.message(caller, F.main("Clans", "This is not a hardcore server!"));
+ return;
+ }
ClansManager clansManager = Plugin.getClansManager();
ClanInfo clan = clansManager.getClan(caller);
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/warpoints/WarPointEvasion.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/warpoints/WarPointEvasion.java
index 04be2a159..409658256 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/warpoints/WarPointEvasion.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/warpoints/WarPointEvasion.java
@@ -72,7 +72,7 @@ public class WarPointEvasion extends MiniPlugin
{
Chunk chunk = event.getClaimedChunk();
- if(_chunkCooldown.containsKey(chunk))
+ if (_chunkCooldown.containsKey(chunk))
{
event.setCancelled(true);
event.getClaimer().sendMessage(F.main("Clans", "You cannot claim this chunk for another " + UtilTime.convertString(COOLDOWN_TIME - (System.currentTimeMillis() - _chunkCooldown.get(chunk)), 1, UtilTime.TimeUnit.MINUTES)));
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventManager.java
index 3dd3cd94e..032d86c2f 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventManager.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventManager.java
@@ -5,11 +5,19 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Random;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import com.google.common.collect.Lists;
+
import mineplex.core.MiniPlugin;
import mineplex.core.blockrestore.BlockRestore;
+import mineplex.core.blood.Blood;
import mineplex.core.common.util.C;
-import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilServer;
+import mineplex.core.common.util.UtilWorld;
import mineplex.core.disguise.DisguiseManager;
import mineplex.core.thereallyoldscoreboardapiweshouldremove.ScoreboardManager;
import mineplex.core.thereallyoldscoreboardapiweshouldremove.elements.ScoreboardElement;
@@ -18,33 +26,23 @@ import mineplex.core.updater.event.UpdateEvent;
import mineplex.game.clans.clans.ClansManager;
import mineplex.game.clans.clans.loot.LootManager;
import mineplex.game.clans.clans.regions.ClansRegions;
+import mineplex.game.clans.clans.worldevent.api.EventState;
+import mineplex.game.clans.clans.worldevent.api.WorldEvent;
+import mineplex.game.clans.clans.worldevent.boss.BossArenaLocationFinder;
import mineplex.game.clans.clans.worldevent.command.WorldEventCommand;
+import mineplex.game.clans.clans.worldevent.raid.RaidManager;
import mineplex.minecraft.game.classcombat.Skill.SkillFactory;
import mineplex.minecraft.game.classcombat.Skill.event.SkillTriggerEvent;
-import mineplex.minecraft.game.core.boss.EventCreatureDeathEvent;
-import mineplex.minecraft.game.core.boss.EventState;
-import mineplex.minecraft.game.core.boss.WorldEvent;
-import mineplex.minecraft.game.core.boss.broodmother.SpiderCreature;
-import mineplex.minecraft.game.core.boss.ironwizard.GolemCreature;
-import mineplex.minecraft.game.core.boss.skeletonking.SkeletonCreature;
import mineplex.minecraft.game.core.damage.DamageManager;
-import org.bukkit.Location;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.HandlerList;
-import org.bukkit.plugin.java.JavaPlugin;
-
-import com.google.common.collect.Lists;
-
public class WorldEventManager extends MiniPlugin implements ScoreboardElement
{
- private static final double ARENA_RADIUS = 40;
private final List _runningEvents;
private Random _random;
private ClansManager _clansManager;
private EventTerrainFinder _terrainFinder;
+ private BossArenaLocationFinder _bossFinder;
private DamageManager _damageManager;
private LootManager _lootManager;
private BlockRestore _blockRestore;
@@ -53,20 +51,27 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
private long _nextEventStart;
+ private RaidManager _raidManager;
+
public WorldEventManager(JavaPlugin plugin, ClansManager clansManager, DamageManager damageManager, LootManager lootManager, BlockRestore blockRestore, ClansRegions clansRegions, SkillFactory skillFactory)
{
super("World Event", plugin);
_random = new Random();
_terrainFinder = new EventTerrainFinder(clansManager);
+ _bossFinder = new BossArenaLocationFinder(UtilWorld.getWorld("world"));
_clansManager = clansManager;
_damageManager = damageManager;
_lootManager = lootManager;
_blockRestore = blockRestore;
- _runningEvents = new LinkedList();
+ _runningEvents = new LinkedList<>();
_skillFactory = skillFactory;
+ new Blood(plugin);
+
+ _raidManager = new RaidManager(plugin);
+
updateNextEventTime();
}
@@ -75,24 +80,22 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
addCommand(new WorldEventCommand(this));
}
- // PS: This never gets called
@Override
public void disable()
{
for (WorldEvent event : _runningEvents)
{
- event.cancel();
+ event.stop(true);
}
+ _runningEvents.clear();
+ _raidManager.onDisable();
}
public boolean isInEvent(Location location)
{
for (WorldEvent event : _runningEvents)
{
- if (UtilMath.offset2d(location, event.getCenterLocation()) <= ARENA_RADIUS)
- {
- return true;
- }
+ event.isInBounds(location, true);
}
return false;
@@ -103,28 +106,9 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
{
if (event.GetSkillName().equalsIgnoreCase("Ice Prison"))
{
- for (WorldEvent e : _runningEvents)
+ if (isInEvent(event.GetPlayer().getLocation()))
{
- if (isInEvent(event.GetPlayer().getLocation()))
- {
- event.SetCancelled(true);
- }
- }
- }
- }
-
- @EventHandler
- public void onBossDeath(EventCreatureDeathEvent event)
- {
- if (event.getCreature() instanceof GolemCreature || event.getCreature() instanceof SkeletonCreature || event.getCreature() instanceof SpiderCreature)
- {
- Location drop = event.getCreature().getLastKnownLocation();
- if (drop != null)
- {
- runSyncLater(() ->
- {
- ClansManager.getInstance().getLootManager().dropRare(drop);
- }, 20 * 2);
+ event.SetCancelled(true);
}
}
}
@@ -137,26 +121,7 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
return;
}
- boolean removed = false;
-
- Iterator iterator = _runningEvents.iterator();
- while (iterator.hasNext())
- {
- WorldEvent worldEvent = iterator.next();
- if (worldEvent.getState() == EventState.COMPLETE || worldEvent.getState() == EventState.CANCELLED)
- {
- HandlerList.unregisterAll(worldEvent);
- iterator.remove();
-
- // If the event was cancelled, cleanup was already done.
- if (worldEvent.getState() == EventState.COMPLETE)
- {
- worldEvent.cleanup();
- }
-
- removed = true;
- }
- }
+ boolean removed = _runningEvents.removeIf(e -> e.getState() == EventState.STOPPED);
if (removed && _runningEvents.size() == 0)
{
@@ -191,19 +156,25 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
private WorldEventType tryStartEvent()
{
WorldEventType[] types = WorldEventType.values();
- WorldEventType type = types[_random.nextInt(types.length)];
- Location location = _terrainFinder.findAreaInBorderlands(false);
- if (location != null)
+ if (types.length == 0)
{
- initializeEvent(type.createInstance(this, location, _skillFactory));
- return type;
+ return null;
}
else
{
- // Try again in 5 minutes
- _nextEventStart = System.currentTimeMillis() + (5 * 60 * 1000);
+ WorldEventType type = types[_random.nextInt(types.length)];
+ //Location location = _terrainFinder.findAreaInBorderlands(false);
+ //if (location != null)
+ {
+ initializeEvent(type.createInstance(this));
+ return type;
+ }
+ //else
+ //{
+ // Try again in 5 minutes
+ //_nextEventStart = System.currentTimeMillis() + (5 * 60 * 1000);
+ //}
}
- return null;
}
private void initializeEvent(WorldEvent event)
@@ -213,30 +184,33 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
throw new RuntimeException("WorldEvent may not be null");
}
- event.loadMap();
event.start();
- getPlugin().getServer().getPluginManager().registerEvents(event, getPlugin());
_runningEvents.add(event);
}
-
- public WorldEvent startEventFromName(Location location, String name)
+
+ public WorldEvent startEventFromName(String name)
{
WorldEventType eventType = WorldEventType.valueOf(name);
if (eventType != null)
{
- WorldEvent event = eventType.createInstance(this, location, _skillFactory);
+ WorldEvent event = eventType.createInstance(this);
+ if (event == null)
+ {
+ return null;
+ }
initializeEvent(event);
return event;
}
return null;
}
+
public WorldEvent startEventFromType(WorldEventType eventType)
{
if (eventType != null)
{
- Location location = _terrainFinder.findAreaInBorderlands(true);
- WorldEvent event = eventType.createInstance(this, location, _skillFactory);
+ //Location location = _terrainFinder.findAreaInBorderlands(true);
+ WorldEvent event = eventType.createInstance(this);
if (event != null)
{
initializeEvent(event);
@@ -253,8 +227,7 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
while (iterator.hasNext())
{
WorldEvent event = iterator.next();
- if (event.getState() != EventState.COMPLETE) event.cancel();
- HandlerList.unregisterAll(event);
+ event.stop(true);
iterator.remove();
}
@@ -281,6 +254,16 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
return _terrainFinder;
}
+ public BossArenaLocationFinder getBossArenaLocationFinder()
+ {
+ return _bossFinder;
+ }
+
+ public RaidManager getRaidManager()
+ {
+ return _raidManager;
+ }
+
private void updateNextEventTime()
{
// 45 Minutes + (0 - 15 Minutes)
@@ -341,4 +324,4 @@ public class WorldEventManager extends MiniPlugin implements ScoreboardElement
{
return getClans().getDisguiseManager();
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventType.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventType.java
index 0110ae6c9..2580c7a9e 100644
--- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventType.java
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/WorldEventType.java
@@ -1,73 +1,45 @@
package mineplex.game.clans.clans.worldevent;
-import java.lang.reflect.Constructor;
-
-import org.bukkit.Location;
-
-import mineplex.minecraft.game.classcombat.Skill.SkillFactory;
-import mineplex.minecraft.game.core.boss.WorldEvent;
-import mineplex.minecraft.game.core.boss.ironwizard.GolemBoss;
-import mineplex.minecraft.game.core.boss.skeletonking.SkeletonBoss;
+import mineplex.game.clans.clans.worldevent.api.WorldEvent;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemBoss;
+import mineplex.game.clans.clans.worldevent.boss.skeletonking.SkeletonBoss;
public enum WorldEventType
{
//SLIME_KING("Slime King", SlimeBoss.class, 30),
//KING_OF_THE_HILL("King of The Hill", KingHill.class, 30),
//UNDEAD_CAMP("Undead Camp", UndeadCamp.class, 30),
- IRON_WIZARD("Iron Wizard",GolemBoss.class, 30),
+ //IRON_WIZARD("Iron Wizard", GolemBoss.class, 30),
//BROOD_MOTHER("Brood Mother", SpiderBoss.class, 30),
- SKELETON_KING("Skeleton King", SkeletonBoss.class, 30);
+ //SKELETON_KING("Skeleton King", SkeletonBoss.class, 30)
+ IRON_WIZARD("Iron Wizard", GolemBoss.class, (man) ->
+ {
+ return new GolemBoss(man);
+ }),
+ SKELETON_KING("Skeleton King", SkeletonBoss.class, (man) ->
+ {
+ return new SkeletonBoss(man);
+ })
+ ;
private String _name;
private Class extends WorldEvent> _clazz;
- private int _areaNeeded;
+ private EventCreator _creator;
- WorldEventType(String name, Class extends WorldEvent> clazz, int areaNeeded)
+ WorldEventType(String name, Class extends WorldEvent> clazz, EventCreator creator)
{
_name = name;
_clazz = clazz;
- _areaNeeded = areaNeeded;
+ _creator = creator;
}
- public int getAreaNeeded()
- {
- return _areaNeeded;
- }
-
- public WorldEvent createInstance(WorldEventManager eventManager, Location centerLocation, SkillFactory skillFactory)
+ public WorldEvent createInstance(WorldEventManager eventManager)
{
WorldEvent worldEvent = null;
- try
+ if (_creator != null)
{
- for (Constructor> con : _clazz.getConstructors())
- {
- Class>[] classes = con.getParameterTypes();
-
- if (classes[0] == WorldEventManager.class)
- {
- if (classes.length == 3)
- {
- worldEvent = (WorldEvent) con.newInstance(eventManager, centerLocation, skillFactory);
- }
- else
- {
- worldEvent = (WorldEvent) con.newInstance(eventManager, centerLocation);
- }
- }
- else if (classes.length == 4)
- {
- worldEvent = (WorldEvent) con.newInstance(eventManager.getDamage(), eventManager.getBlockRestore(), eventManager.getClans().getCondition(), centerLocation);
- }
- else
- {
- worldEvent = (WorldEvent) con.newInstance(eventManager.getDisguiseManager(), eventManager.getDamage(), eventManager.getBlockRestore(), eventManager.getClans().getCondition(), eventManager.getClans().getProjectile(), centerLocation);
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
+ worldEvent = _creator.createEvent(eventManager);
}
return worldEvent;
@@ -75,6 +47,11 @@ public enum WorldEventType
public String getName()
{
- return this._name;
+ return _name;
}
-}
+
+ private static interface EventCreator
+ {
+ WorldEvent createEvent(WorldEventManager manager);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossAbility.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossAbility.java
new file mode 100644
index 000000000..8ed1186c1
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossAbility.java
@@ -0,0 +1,109 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Listener;
+
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilTime;
+
+public abstract class BossAbility, Y extends LivingEntity> implements Listener
+{
+ private T _creature;
+ private Map _damaged = new HashMap<>();
+
+ public BossAbility(T creature)
+ {
+ _creature = creature;
+ }
+
+ public abstract boolean canMove();
+
+ public abstract boolean inProgress();
+
+ public abstract boolean hasFinished();
+
+ public abstract void setFinished();
+
+ public abstract void tick();
+
+ public boolean canDamage(Entity player)
+ {
+ if (_damaged.containsKey(player.getUniqueId()))
+ {
+
+ if (!UtilTime.elapsed(_damaged.get(player.getUniqueId()), 400))
+ {
+ return false;
+ }
+ }
+
+ _damaged.put(player.getUniqueId(), System.currentTimeMillis());
+ return true;
+ }
+
+ public int getCooldown()
+ {
+ return 3;
+ }
+
+ public Y getEntity()
+ {
+ return getBoss().getEntity();
+ }
+
+ public T getBoss()
+ {
+ return _creature;
+ }
+
+ public Location getLocation()
+ {
+ return getEntity().getLocation();
+ }
+
+ public Player getTarget()
+ {
+ return getTarget(30);
+ }
+
+ public Player getTarget(double minDistance, double maxDistance)
+ {
+ Player target = null;
+ double dist = 0;
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), maxDistance, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(getLocation());
+
+ if (d < minDistance)
+ {
+ continue;
+ }
+
+ if (target == null || dist > d)
+ {
+ target = player;
+ dist = d;
+ }
+ }
+
+ return target;
+ }
+
+ public Player getTarget(double maxDistance)
+ {
+ return getTarget(0, maxDistance);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossPassive.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossPassive.java
new file mode 100644
index 000000000..c2387ea0d
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/BossPassive.java
@@ -0,0 +1,50 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.event.Listener;
+
+import mineplex.core.common.util.UtilServer;
+
+public abstract class BossPassive, Y extends LivingEntity> implements Listener
+{
+ private T _creature;
+ private final int _cooldown;
+
+ public BossPassive(T creature)
+ {
+ this(creature, 30);
+ }
+
+ public BossPassive(T creature, int cooldown)
+ {
+ _creature = creature;
+ _cooldown = cooldown;
+ Bukkit.getPluginManager().registerEvents(this, UtilServer.getPlugin());
+ }
+
+ public abstract boolean isProgressing();
+
+ public abstract void tick();
+
+ public int getCooldown()
+ {
+ return _cooldown;
+ }
+
+ public Y getEntity()
+ {
+ return getBoss().getEntity();
+ }
+
+ public T getBoss()
+ {
+ return _creature;
+ }
+
+ public Location getLocation()
+ {
+ return getEntity().getLocation();
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventArena.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventArena.java
new file mode 100644
index 000000000..3169e9532
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventArena.java
@@ -0,0 +1,44 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+import org.bukkit.Location;
+
+import mineplex.core.common.util.UtilMath;
+
+public class EventArena
+{
+ private final Location _centerLocation;
+ private final double _radius;
+ private final double _radiusSquared;
+
+ public EventArena(Location center, double radius)
+ {
+ _centerLocation = center;
+ _radius = radius;
+ _radiusSquared = Math.pow(radius, 2);
+ }
+
+ public Location getCenterLocation()
+ {
+ return _centerLocation;
+ }
+
+ public double getRadius()
+ {
+ return _radius;
+ }
+
+ public double getRadiusSquared()
+ {
+ return _radiusSquared;
+ }
+
+ public boolean isInArena(Location checkLocation, boolean flat)
+ {
+ if (flat)
+ {
+ return UtilMath.offset2dSquared(checkLocation, _centerLocation) <= _radiusSquared;
+ }
+
+ return UtilMath.offsetSquared(checkLocation, _centerLocation) <= _radiusSquared;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreature.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreature.java
new file mode 100644
index 000000000..43326c031
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreature.java
@@ -0,0 +1,412 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+import java.util.UUID;
+
+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.EntityCombustEvent;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.world.ChunkUnloadEvent;
+
+import mineplex.core.common.util.C;
+import mineplex.core.common.util.UtilAlg;
+import mineplex.core.common.util.UtilMath;
+import mineplex.core.common.util.UtilTime;
+import mineplex.core.disguise.disguises.DisguiseBase;
+import mineplex.core.disguise.disguises.DisguiseInsentient;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.minecraft.game.core.condition.Condition.ConditionType;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+
+public abstract class EventCreature implements Listener
+{
+ protected static final boolean DEBUG_MODE = true;
+ private static final long TELEPORT_HOME_WARMUP = 5000;
+ private static final long HEALTH_REGEN_COOLDOWN = 1500;
+ private static final long SAFE_TO_HEALTH_REGEN_COOLDOWN = 15000;
+ private static final double HEALTH_PER_REGEN = 1.5;
+
+ private WorldEvent _event;
+
+ // Spawn Data
+ private T _entity;
+ private Class extends T> _entityClass;
+ private Location _spawnLocation, _lastLocation;
+
+ // Creature Data
+ private String _name;
+ private String _displayName;
+ private boolean _useName;
+ private double _health;
+ private double _maxHealth;
+ private boolean _showHealthName;
+ private long _teleportHome;
+ private double _walkRange;
+ private boolean _healthRegen;
+
+ // Fight Data
+ private long _lastDamaged;
+ private UUID _lastDamager;
+ private long _lastRegen;
+
+ public EventCreature(WorldEvent event, Location spawnLocation, String name, boolean useName, double health, double walkRange, boolean healthRegen, Class entityClass)
+ {
+ _event = event;
+
+ _entityClass = entityClass;
+ _spawnLocation = spawnLocation;
+
+ _name = name;
+ _displayName = name;
+ _useName = useName;
+ _health = health;
+ _maxHealth = health;
+ _showHealthName = true;
+ _teleportHome = -1L;
+ _walkRange = walkRange;
+ _healthRegen = healthRegen;
+ }
+
+ public double getDifficulty()
+ {
+ return getEvent().getDifficulty();
+ }
+
+ protected void spawnEntity()
+ {
+ Location spawnLocation = _entity == null ? _spawnLocation : _entity.getLocation();
+ T entity = _spawnLocation.getWorld().spawn(spawnLocation, getEntityClass());
+
+ setEntity(entity);
+ updateEntityHealth();
+ entity.setRemoveWhenFarAway(false);
+ spawnCustom();
+ updateName();
+ }
+
+ protected abstract void spawnCustom();
+
+ protected void updateEntityHealth()
+ {
+ _entity.setMaxHealth(500d);
+ _entity.setHealth(500d);
+ }
+
+ protected void updateName()
+ {
+ String name = _displayName;
+
+ if (_showHealthName)
+ {
+ String healthString = (int) _health + "/" + (int) _maxHealth;
+ double per =_health / _maxHealth;
+ if (per > 0.5) healthString = C.cGreen + healthString;
+ if (per > 0.2) healthString = C.cYellow + healthString;
+ else healthString = C.cRed + healthString;
+
+ name += " " + C.cWhite + "(" + healthString + C.cWhite + ")";
+ }
+
+ DisguiseBase disguise = getEvent().getDisguiseManager().getActiveDisguise(getEntity());
+
+ if (disguise != null && disguise instanceof DisguiseInsentient)
+ {
+ ((DisguiseInsentient) disguise).setName(name);
+ ((DisguiseInsentient) disguise).setCustomNameVisible(_useName);
+ }
+
+ _entity.setCustomName(name);
+ _entity.setCustomNameVisible(_useName);
+ }
+
+ public void remove()
+ {
+ remove(true);
+ }
+
+ public void remove(boolean removeFromEvent)
+ {
+ if (_entity != null)
+ {
+ if (getHealth() > 0)
+ {
+ _entity.remove();
+ }
+ else
+ {
+ _entity.setHealth(0);
+ _entity.setCustomName("");
+ _entity.setCustomNameVisible(false);
+ }
+ }
+
+ if (removeFromEvent)
+ {
+ _event.removeCreature(this);
+ }
+ }
+
+ protected final void die()
+ {
+ dieCustom();
+ remove();
+ }
+
+ public abstract void dieCustom();
+
+ public WorldEvent getEvent()
+ {
+ return _event;
+ }
+
+ public void setEvent(WorldEvent event)
+ {
+ _event = event;
+ }
+
+ public T getEntity()
+ {
+ return _entity;
+ }
+
+ public void setEntity(T entity)
+ {
+ if (_entity != null) _entity.remove();
+
+ _entity = entity;
+ }
+
+ public Class extends T> getEntityClass()
+ {
+ return _entityClass;
+ }
+
+ public void setEntityClass(Class extends T> clazz)
+ {
+ _entityClass = clazz;
+ }
+
+ public double getHealthPercent()
+ {
+ return getHealth() / getMaxHealth();
+ }
+
+ public Location getSpawnLocation()
+ {
+ return _spawnLocation;
+ }
+
+ public Location getLastKnownLocation()
+ {
+ return _lastLocation;
+ }
+
+ public void setSpawnLocation(Location spawnLocation)
+ {
+ _spawnLocation = spawnLocation;
+ }
+
+ public String getDisplayName()
+ {
+ return _displayName;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public void setName(String name)
+ {
+ _displayName = name == null ? _name : name;
+ updateName();
+ }
+
+ public boolean isUseName()
+ {
+ return _useName;
+ }
+
+ public void setUseName(boolean useName)
+ {
+ _useName = useName;
+ updateName();
+ }
+
+ public void applyDamage(double damage)
+ {
+ setHealth(getHealth() - damage);
+ }
+
+ public void applyRegen(double regen)
+ {
+ setHealth(getHealth() + regen);
+ }
+
+ public double getHealth()
+ {
+ return _health;
+ }
+
+ public void setHealth(double health)
+ {
+ _health = Math.min(health, getMaxHealth());
+
+ if (_health <= 0)
+ {
+ die();
+ }
+ else
+ {
+ updateName();
+ }
+ }
+
+ public double getMaxHealth()
+ {
+ return _maxHealth;
+ }
+
+ public void setMaxHealth(double maxHealth)
+ {
+ _maxHealth = maxHealth;
+ }
+
+ public void setShowHealthName(boolean showHealthName)
+ {
+ _showHealthName = showHealthName;
+ updateName();
+ }
+
+ /**
+ * Event listeners
+ */
+
+ @EventHandler
+ public void onChunkUnload(ChunkUnloadEvent event)
+ {
+ if (_entity != null && _entity.getLocation().getChunk().equals(event.getChunk()))
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void update(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.FAST)
+ {
+ return;
+ }
+
+ if (_entity == null || _entity.isDead() || !_entity.isValid())
+ {
+ if (DEBUG_MODE)
+ {
+ System.out.println("Respawning " + getName() + " because it is null or dead");
+ }
+ spawnEntity();
+ }
+
+ if (_healthRegen && getHealth() < getMaxHealth() && UtilTime.elapsed(_lastDamaged, SAFE_TO_HEALTH_REGEN_COOLDOWN) && UtilTime.elapsed(_lastRegen, HEALTH_REGEN_COOLDOWN))
+ {
+ _lastRegen = System.currentTimeMillis();
+ applyRegen(HEALTH_PER_REGEN);
+ }
+
+ if (_walkRange != -1 && UtilMath.offset2d(_entity.getLocation(), _spawnLocation) > _walkRange)
+ {
+ if (_teleportHome != -1 && System.currentTimeMillis() >= _teleportHome)
+ {
+ _entity.teleport(_spawnLocation);
+ _teleportHome = -1;
+ }
+ else
+ {
+ _entity.setVelocity(UtilAlg.getTrajectory(_entity.getLocation(), _spawnLocation).normalize().multiply(2));
+ if (_teleportHome == -1)
+ {
+ _teleportHome = System.currentTimeMillis() + TELEPORT_HOME_WARMUP;
+ }
+ }
+ }
+ else
+ {
+ if (_teleportHome != -1)
+ {
+ _teleportHome = -1;
+ }
+ }
+
+ _lastLocation = _entity.getLocation();
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onDamage(CustomDamageEvent event)
+ {
+ if (_entity == null)
+ {
+ return;
+ }
+
+ if (!event.GetDamageeEntity().equals(_entity))
+ {
+ return;
+ }
+
+ updateEntityHealth();
+
+ applyDamage(event.GetDamage());
+ updateName();
+
+ _lastDamaged = System.currentTimeMillis();
+
+ _event.updateLastActive();
+ }
+
+ @EventHandler
+ public void damageType(CustomDamageEvent event)
+ {
+ if (_entity == null)
+ {
+ return;
+ }
+
+ if (!event.GetDamageeEntity().equals(_entity))
+ {
+ return;
+ }
+
+ DamageCause cause = event.GetCause();
+
+ if (cause == DamageCause.FALL && !getEvent().getCondition().HasCondition(_entity, ConditionType.FALLING, null))
+ {
+ event.SetCancelled("Cancel");
+ }
+
+ if (cause == DamageCause.DROWNING || cause == DamageCause.SUFFOCATION)
+ {
+ event.SetCancelled("Cancel");
+ }
+ }
+
+ @EventHandler
+ public void cancelCombust(EntityCombustEvent event)
+ {
+ if (_entity == null)
+ {
+ return;
+ }
+
+ if (!event.getEntity().equals(_entity))
+ {
+ return;
+ }
+
+ event.setCancelled(true);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreatureDeathEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreatureDeathEvent.java
new file mode 100644
index 000000000..8141b4745
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventCreatureDeathEvent.java
@@ -0,0 +1,31 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class EventCreatureDeathEvent extends Event
+{
+ private static final HandlerList handlers = new HandlerList();
+
+ private final EventCreature> _creature;
+
+ public EventCreatureDeathEvent(EventCreature> creature)
+ {
+ _creature = creature;
+ }
+
+ public EventCreature> getCreature()
+ {
+ return _creature;
+ }
+
+ public HandlerList getHandlers()
+ {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList()
+ {
+ return handlers;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventState.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventState.java
new file mode 100644
index 000000000..bdee54454
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/EventState.java
@@ -0,0 +1,9 @@
+package mineplex.game.clans.clans.worldevent.api;
+
+public enum EventState
+{
+ LOADING,
+ LIVE,
+ STOPPED,
+ REMOVED
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/WorldEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/WorldEvent.java
new file mode 100644
index 000000000..1790cc269
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/api/WorldEvent.java
@@ -0,0 +1,337 @@
+ package mineplex.game.clans.clans.worldevent.api;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+
+import mineplex.core.blockrestore.BlockRestore;
+import mineplex.core.blockrestore.BlockRestoreMap;
+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.common.util.UtilServer;
+import mineplex.core.common.util.UtilTextMiddle;
+import mineplex.core.common.util.UtilWorld;
+import mineplex.core.disguise.DisguiseManager;
+import mineplex.core.projectile.ProjectileManager;
+import mineplex.core.thereallyoldscoreboardapiweshouldremove.ScoreboardManager;
+import mineplex.core.thereallyoldscoreboardapiweshouldremove.elements.ScoreboardElement;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.minecraft.game.core.condition.ConditionManager;
+import mineplex.minecraft.game.core.damage.DamageManager;
+
+public abstract class WorldEvent implements Listener, ScoreboardElement
+{
+ // 20 Minutes
+ private static final int ACTIVE_TIMEOUT = 1200000;
+ private static final int LOADING_TIMEOUT = 300000;
+
+ private DamageManager _damageManager;
+ private ConditionManager _conditionManager;
+ private DisguiseManager _disguiseManager;
+ private ProjectileManager _projectileManager;
+
+ private String _name;
+ private EventState _state;
+ private EventArena _arena;
+ private Random _random;
+ private long _timeStarted;
+ private long _lastActive;
+ private boolean _announceStart;
+
+ // Creatures
+ private List> _creatures;
+ // Block Restore
+ private BlockRestoreMap _blockRestoreMap;
+ private double _difficulty = 1;
+
+ public WorldEvent(String name, Location centerLocation, double radius, boolean announceStart, DisguiseManager disguiseManager, ProjectileManager projectileManager, DamageManager damageManager, BlockRestore blockRestore, ConditionManager conditionManager)
+ {
+ _disguiseManager = disguiseManager;
+ _projectileManager = projectileManager;
+ _damageManager = damageManager;
+ _conditionManager = conditionManager;
+
+ _name = name;
+ _state = EventState.LOADING;
+ _arena = new EventArena(centerLocation, radius);
+ _random = new Random();
+ _announceStart = announceStart;
+
+ _creatures = new ArrayList<>();
+ _blockRestoreMap = blockRestore.createMap();
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public void setName(String name)
+ {
+ _name = name;
+ }
+
+ public EventArena getEventArena()
+ {
+ return _arena;
+ }
+
+ public EventState getState()
+ {
+ return _state;
+ }
+
+ protected void setState(EventState state)
+ {
+ _state = state;
+ }
+
+ public double getDifficulty()
+ {
+ return _difficulty;
+ }
+
+ public void setDifficulty(double difficulty)
+ {
+ _difficulty = difficulty;
+ }
+
+ public Location getCenterLocation()
+ {
+ return _arena.getCenterLocation();
+ }
+
+ public List> getCreatures()
+ {
+ return _creatures;
+ }
+
+ public void registerCreature(EventCreature> creature)
+ {
+ UtilServer.RegisterEvents(creature);
+ _creatures.add(creature);
+ }
+
+ public void removeCreature(EventCreature> creature)
+ {
+ Bukkit.getPluginManager().callEvent(new EventCreatureDeathEvent(creature));
+ HandlerList.unregisterAll(creature);
+ _creatures.remove(creature);
+ }
+
+ public void clearCreatures()
+ {
+ for (EventCreature> creature : _creatures)
+ {
+ creature.remove(false);
+ HandlerList.unregisterAll(creature);
+ }
+
+ _creatures.clear();
+ }
+
+ public long getTimeRunning()
+ {
+ return System.currentTimeMillis() - _timeStarted;
+ }
+
+ public long getLastActive()
+ {
+ return _lastActive;
+ }
+
+ public void updateLastActive()
+ {
+ _lastActive = System.currentTimeMillis();
+ }
+
+ public boolean isInBounds(Location location, boolean flat)
+ {
+ return _arena.isInArena(location, flat);
+ }
+
+ protected Random getRandom()
+ {
+ return _random;
+ }
+
+ public DisguiseManager getDisguiseManager()
+ {
+ return _disguiseManager;
+ }
+
+ public ProjectileManager getProjectileManager()
+ {
+ return _projectileManager;
+ }
+
+ public DamageManager getDamageManager()
+ {
+ return _damageManager;
+ }
+
+ public ConditionManager getCondition()
+ {
+ return _conditionManager;
+ }
+
+ protected BlockRestoreMap getBlockRestoreMap()
+ {
+ return _blockRestoreMap;
+ }
+
+ public void setBlock(Block block, Material material)
+ {
+ setBlock(block, material, (byte) 0);
+ }
+
+ @SuppressWarnings("deprecation")
+ public void setBlock(Block block, Material material, byte data)
+ {
+ setBlock(block, material.getId(), data);
+ }
+
+ public void setBlock(Block block, int id, byte data)
+ {
+ _blockRestoreMap.set(block, id, data);
+ }
+
+ public void restoreBlocks()
+ {
+ _blockRestoreMap.restore();
+ }
+
+ public final void start()
+ {
+ _timeStarted = System.currentTimeMillis();
+ _lastActive = System.currentTimeMillis();
+ if (_announceStart)
+ {
+ announceStart();
+ }
+ setState(EventState.LIVE);
+ customStart();
+ UtilServer.RegisterEvents(this);
+ }
+
+ public void announceStart()
+ {
+ UtilTextMiddle.display(C.cGreen + getName(), UtilWorld.locToStrClean(getCenterLocation()), 10, 100, 40);
+
+ UtilServer.broadcast(F.main("Event", F.elem(getName()) + " has started at coordinates " + F.elem(UtilWorld.locToStrClean(getCenterLocation()))));
+ }
+
+ protected abstract void customStart();
+
+ protected abstract void customTick();
+
+ public final void cleanup(boolean onDisable)
+ {
+ clearCreatures();
+ restoreBlocks();
+ customCleanup(onDisable);
+ }
+
+ public abstract void customCleanup(boolean onDisable);
+
+ public final void stop()
+ {
+ stop(false);
+ }
+
+ public final void stop(boolean onDisable)
+ {
+ cleanup(onDisable);
+ if (onDisable)
+ {
+ setState(EventState.REMOVED);
+ }
+ else
+ {
+ setState(EventState.STOPPED);
+ }
+ customStop();
+ HandlerList.unregisterAll(this);
+ }
+
+ protected abstract void customStop();
+
+ public int getRandomRange(int min, int max)
+ {
+ return min + _random.nextInt(UtilMath.clamp(max - min, min, max));
+ }
+
+ public void announceMessage(String message)
+ {
+ UtilServer.broadcast(F.main("Event", F.elem(getName()) + ": " + message));
+ }
+
+ public void sendMessage(Player player, String message)
+ {
+ UtilPlayer.message(player, F.main("Event", F.elem(getName()) + ": " + message));
+ }
+
+ @EventHandler
+ public void tick(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ customTick();
+ }
+
+ @EventHandler
+ public void endInactive(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.SEC)
+ {
+ return;
+ }
+
+ long diff = System.currentTimeMillis() - getLastActive();
+ if (diff > ACTIVE_TIMEOUT)
+ {
+ stop();
+ }
+ }
+
+ @EventHandler
+ public void prepareTimeout(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.SEC)
+ {
+ return;
+ }
+
+ if (getState() != EventState.LOADING)
+ {
+ return;
+ }
+
+ // Event was preparing for more than 5 minutes
+ if (getTimeRunning() > LOADING_TIMEOUT)
+ {
+ stop();
+ }
+ }
+
+ @Override
+ public List getLines(ScoreboardManager manager, Player player, List out)
+ {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossArenaLocationFinder.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossArenaLocationFinder.java
new file mode 100644
index 000000000..a4c6bbc62
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossArenaLocationFinder.java
@@ -0,0 +1,66 @@
+package mineplex.game.clans.clans.worldevent.boss;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.Pair;
+
+public class BossArenaLocationFinder
+{
+ private World _world;
+
+ public BossArenaLocationFinder(World world)
+ {
+ _world = world;
+ }
+
+ public Location getIronWizardCenter()
+ {
+ return new Location(_world, 1057, 63, -77);
+ }
+
+ public Pair, List> getIronWizardPads()
+ {
+ List in = new ArrayList<>();
+ List out = new ArrayList<>();
+
+ in.add(new Vector(1006, 62, -77));
+ in.add(new Vector(1057, 62, -26));
+ in.add(new Vector(1108, 62, -77));
+ in.add(new Vector(1057, 62, -128));
+
+ out.add(new Vector(1035, 63, -77));
+ out.add(new Vector(1057, 63, -99));
+ out.add(new Vector(1079, 63, -77));
+ out.add(new Vector(1057, 63, -55));
+
+ return Pair.create(in, out);
+ }
+
+ public Location getSkeletonKingCenter()
+ {
+ return new Location(_world, -1043, 58, 159);
+ }
+
+ public Pair, List> getSkeletonKingPads()
+ {
+ List in = new ArrayList<>();
+ List out = new ArrayList<>();
+
+ in.add(new Vector(-1094, 57, 159));
+ in.add(new Vector(-1043, 57, 210));
+ in.add(new Vector(-992, 57, 159));
+ in.add(new Vector(-1043, 57, 108));
+
+ out.add(new Vector(-1021, 58, 159));
+ out.add(new Vector(-1043, 58, 137));
+ out.add(new Vector(-1065, 58, 159));
+ out.add(new Vector(-1043, 58, 181));
+
+ return Pair.create(in, out);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossDeathEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossDeathEvent.java
new file mode 100644
index 000000000..caf9109b3
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossDeathEvent.java
@@ -0,0 +1,39 @@
+package mineplex.game.clans.clans.worldevent.boss;
+
+import org.bukkit.Location;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class BossDeathEvent extends Event
+{
+ private static final HandlerList handlers = new HandlerList();
+
+ private final BossWorldEvent> _event;
+ private final Location _deathLocation;
+
+ public BossDeathEvent(BossWorldEvent> event, Location location)
+ {
+ _event = event;
+ _deathLocation = location;
+ }
+
+ public BossWorldEvent> getEvent()
+ {
+ return _event;
+ }
+
+ public Location getDeathLocation()
+ {
+ return _deathLocation;
+ }
+
+ public HandlerList getHandlers()
+ {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList()
+ {
+ return handlers;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossWorldEvent.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossWorldEvent.java
new file mode 100644
index 000000000..817850ac7
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/BossWorldEvent.java
@@ -0,0 +1,114 @@
+package mineplex.game.clans.clans.worldevent.boss;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+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.util.Vector;
+
+import mineplex.core.blockrestore.BlockRestore;
+import mineplex.core.common.util.C;
+import mineplex.core.common.util.UtilMath;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.disguise.DisguiseManager;
+import mineplex.core.itemstack.ItemBuilder;
+import mineplex.core.projectile.ProjectileManager;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.ClansManager;
+import mineplex.game.clans.clans.worldevent.api.EventCreature;
+import mineplex.game.clans.clans.worldevent.api.EventCreatureDeathEvent;
+import mineplex.game.clans.clans.worldevent.api.EventState;
+import mineplex.game.clans.clans.worldevent.api.WorldEvent;
+import mineplex.minecraft.game.classcombat.Skill.ISkill;
+import mineplex.minecraft.game.classcombat.Skill.Assassin.Recall;
+import mineplex.minecraft.game.core.condition.ConditionManager;
+import mineplex.minecraft.game.core.damage.DamageManager;
+
+public abstract class BossWorldEvent> extends WorldEvent
+{
+ private static final double TELEPORT_PAD_RANGE = 1.5;
+ private static final long DELAY_TILL_DROP_REWARD = 40;
+
+ private T _boss;
+ private List _teleportFrom;
+ private List _teleportTo;
+
+ public BossWorldEvent(String name, Location centerLocation, double radius, List teleportFrom, List teleportTo, DisguiseManager disguiseManager, ProjectileManager projectileManager, DamageManager damageManager, BlockRestore blockRestore, ConditionManager conditionManager)
+ {
+ super(name, centerLocation, radius, true, disguiseManager, projectileManager, damageManager, blockRestore, conditionManager);
+
+ _teleportFrom = teleportFrom.stream().map(vec -> vec.toLocation(centerLocation.getWorld())).collect(Collectors.toList());
+ _teleportTo = teleportTo.stream().map(vec -> vec.toLocation(centerLocation.getWorld())).collect(Collectors.toList());
+ }
+
+ public abstract String getDeathMessage();
+
+ public T getBossCreature()
+ {
+ return _boss;
+ }
+
+ public void setBossCreature(T boss)
+ {
+ _boss = boss;
+ }
+
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.FAST)
+ {
+ return;
+ }
+ if (getState() != EventState.LIVE)
+ {
+ return;
+ }
+ if (_teleportFrom.isEmpty() || _teleportTo.isEmpty())
+ {
+ return;
+ }
+ for (Location from : _teleportFrom)
+ {
+ for (Player player : UtilPlayer.getInRadius(from, TELEPORT_PAD_RANGE).keySet())
+ {
+ player.teleport(UtilMath.randomElement(_teleportTo));
+ for (ISkill skill : ClansManager.getInstance().getClassManager().Get(player).GetSkills())
+ {
+ if (skill instanceof Recall)
+ {
+ ((Recall)skill).Reset(player);
+ }
+ }
+ sendMessage(player, "You have teleported inside the arena!");
+ }
+ }
+ }
+
+ @EventHandler
+ public void onBossDeath(EventCreatureDeathEvent event)
+ {
+ if (_boss == null)
+ {
+ return;
+ }
+ if (event.getCreature().equals(_boss))
+ {
+ Location drop = event.getCreature().getLastKnownLocation();
+ UtilServer.CallEvent(new BossDeathEvent(this, drop));
+ ClansManager.getInstance().runSyncLater(() ->
+ {
+ ClansManager.getInstance().getLootManager().dropRare(drop);
+ drop.getWorld().dropItem(drop, new ItemBuilder(Material.IRON_INGOT).setTitle(C.cDRedB + "Old Silver Token").setLore(C.cRed + "This token pulses with an evil aura.").setGlow(true).build());
+ }, DELAY_TILL_DROP_REWARD);
+ Bukkit.broadcastMessage(getDeathMessage());
+ stop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemBoss.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemBoss.java
new file mode 100644
index 000000000..2d79eea2d
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemBoss.java
@@ -0,0 +1,46 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+
+import mineplex.core.common.util.F;
+import mineplex.game.clans.clans.worldevent.WorldEventManager;
+import mineplex.game.clans.clans.worldevent.boss.BossWorldEvent;
+
+public class GolemBoss extends BossWorldEvent
+{
+ public GolemBoss(WorldEventManager manager)
+ {
+ super("Iron Wizard", manager.getBossArenaLocationFinder().getIronWizardCenter(), 50, manager.getBossArenaLocationFinder().getIronWizardPads().getLeft(), manager.getBossArenaLocationFinder().getIronWizardPads().getRight(), manager.getDisguiseManager(), manager.getClans().getProjectile(), manager.getClans().getDamageManager(), manager.getBlockRestore(), manager.getClans().getCondition());
+ }
+
+ @Override
+ protected void customStart()
+ {
+ Bukkit.broadcastMessage(F.main(getName(), "The mighty " + getName() + " challenges you to face him!"));
+ spawnGolem(getCenterLocation());
+ }
+
+ @Override
+ public String getDeathMessage()
+ {
+ return F.main(getName(), "The mighty " + getName() + " has fallen!");
+ }
+
+ private GolemCreature spawnGolem(Location location)
+ {
+ GolemCreature golemCreature = new GolemCreature(this, location);
+ registerCreature(golemCreature);
+ setBossCreature(golemCreature);
+ return golemCreature;
+ }
+
+ @Override
+ protected void customTick() {}
+
+ @Override
+ public void customCleanup(boolean onDisable) {}
+
+ @Override
+ protected void customStop() {}
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemCreature.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemCreature.java
new file mode 100644
index 000000000..216ede265
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/GolemCreature.java
@@ -0,0 +1,599 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Sound;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Arrow;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.util.Vector;
+
+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.UtilPlayer;
+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.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.api.EventCreature;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemBlockHail;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemBlockShot;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemDeadlyTremor;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemEarthquake;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemExplodingAura;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemIronHook;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemMeleeAttack;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemRupture;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemSlam;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities.GolemSpike;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+
+public class GolemCreature extends EventCreature
+{
+ private int _lastAbility;
+ private long _lastWalked;
+ private Location _standing;
+ private long _spawnDelay = System.currentTimeMillis();
+ private long _reverseWalk;
+ private Map>, Class>[]> _preferredCombos = new HashMap<>();
+ private Class extends BossAbility> _lastAttack;
+ private boolean _usedFinalAttack;
+ private List> _currentAbilities = new ArrayList<>();
+ private double _canDeadlyTremor = 225;
+ private Vector _afkWalk = new Vector();
+ private long _lastSlam;
+
+ public GolemCreature(GolemBoss boss, Location location)
+ {
+ super(boss, location, "Iron Wizard", true, 3000, 30, true, IronGolem.class);
+
+ spawnEntity();
+
+ _preferredCombos.put(GolemEarthquake.class, new Class[]
+ {
+ GolemBlockHail.class, GolemRupture.class
+ });
+ _preferredCombos.put(GolemMeleeAttack.class, new Class[]
+ {
+ GolemEarthquake.class, GolemRupture.class
+ });
+ _preferredCombos.put(GolemDeadlyTremor.class, new Class[]
+ {
+ GolemMeleeAttack.class
+ });
+ _preferredCombos.put(GolemBlockShot.class, new Class[]
+ {
+ GolemEarthquake.class
+ });
+ _preferredCombos.put(GolemRupture.class, new Class[]
+ {
+ GolemBlockShot.class
+ });
+ _preferredCombos.put(GolemBlockHail.class, new Class[]
+ {
+ GolemDeadlyTremor.class
+ });
+ }
+
+ private boolean hasFurther(Map distances, double range)
+ {
+ for (Player player : distances.keySet())
+ {
+ if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR)
+ {
+ continue;
+ }
+
+ Double dist = distances.get(player);
+ if (dist >= range)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void spawnCustom()
+ {
+ UtilEnt.vegetate(getEntity());
+ _standing = getEntity().getLocation();
+ }
+
+ @SuppressWarnings("unchecked")
+ @EventHandler
+ public void abilityTick(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ if (!UtilTime.elapsed(_spawnDelay, 5000))
+ {
+ _standing = getEntity().getLocation();
+ return;
+ }
+
+ Iterator> itel = _currentAbilities.iterator();
+ boolean canDoNew = _currentAbilities.size() < 3;
+
+ while (itel.hasNext())
+ {
+ BossAbility ability = itel.next();
+
+ if (ability.hasFinished())
+ {
+ itel.remove();
+ ability.setFinished();
+ _lastAbility = 20;
+
+ HandlerList.unregisterAll(ability);
+ if (DEBUG_MODE)
+ {
+ System.out.print("Unregistered golem ability " + ability.getClass().getSimpleName());
+ }
+ }
+ else if (!ability.inProgress())
+ {
+ canDoNew = false;
+ }
+ }
+
+ if (_lastAbility-- <= 0 && canDoNew && UtilBlock.solid(getEntity().getLocation().getBlock().getRelative(BlockFace.DOWN)))
+ {
+ Map>, Integer> weight = new HashMap<>();
+ Map dist = new HashMap<>();
+
+ for (Player player : UtilPlayer.getNearby(getEntity().getLocation(), 50, true))
+ {
+ if (player.hasLineOfSight(getEntity()))
+ {
+ dist.put(player, player.getLocation().distance(getEntity().getLocation()));
+ }
+ }
+
+ if (!dist.isEmpty())
+ {
+ double hp = getHealthPercent();
+
+ { // Melee
+ List players = getPlayers(dist, UtilMath.r(10) == 0 ? 4 : 3);
+
+ if (!players.isEmpty())
+ {
+ if (players.size() >= 4)
+ {
+ weight.put(GolemEarthquake.class, 999);
+ }
+ else
+ {
+ weight.put(GolemMeleeAttack.class, 999);
+ }
+ }
+ }
+
+ if (hasFurther(dist, 15))
+ { // Iron Hook
+ weight.put(GolemIronHook.class, 6); //6
+ }
+
+ if (hp < 0.7)
+ { // Earthquake
+ List players = getPlayers(dist, 10);
+
+ double score = 0;
+
+ for (Player player : players)
+ {
+ score += (8 - dist.get(player)) / 2;
+ }
+
+ if (players.size() >= 3)
+ {
+ score += 7;
+ }
+
+ if (score > 0)
+ {
+ weight.put(GolemEarthquake.class, (int) Math.ceil(score));
+ }
+ }
+
+ { // Wall explode
+ if (!getPlayers(dist, 20).isEmpty() && getPlayers(dist, 4).isEmpty())
+ {
+ weight.put(GolemSpike.class, 8);
+ }
+ }
+
+ { // Block Shot
+ List players = getPlayers(dist, 30);
+
+ for (Player player : players)
+ {
+ if (dist.get(player) > 4)
+ {
+ weight.put(GolemBlockShot.class, 6);
+ break;
+ }
+ }
+ }
+
+ { // Rupture
+ List players = getPlayers(dist, 30);
+
+ if (!players.isEmpty())
+ {
+ weight.put(GolemRupture.class, (int) Math.min(5, dist.get(players.get(0))));
+ }
+ }
+
+ { // Slam
+ List players = getPlayers(dist, 30);
+
+ if (!players.isEmpty() && UtilTime.elapsed(_lastSlam, 20000))
+ {
+ weight.put(GolemSlam.class, 6);
+ }
+ }
+
+ if (_canDeadlyTremor <= 0) // Deadly Tremor
+ {
+ List players = getPlayers(dist, 80);
+
+ for (BossAbility ability : _currentAbilities)
+ {
+ if (ability instanceof GolemExplodingAura)
+ {
+ players.clear();
+ }
+ }
+
+ if (!players.isEmpty())
+ {
+ weight.put(GolemDeadlyTremor.class, (int) 30);
+ }
+ }
+
+ {// Block Hail
+ List players = getPlayers(dist, 30);
+
+ if (!players.isEmpty())
+ {
+ int we = _lastAttack == GolemEarthquake.class ? 20 : UtilMath.r(15) - 2;
+
+ if (we > 0)
+ {
+ weight.put(GolemBlockHail.class, we);
+ }
+ }
+ }
+
+ if (!_usedFinalAttack && getHealth() < 90)
+ {
+ _usedFinalAttack = true;
+ weight.clear();
+
+ weight.put(GolemExplodingAura.class, 999);
+ }
+
+ if (_lastAttack != null && _preferredCombos.containsKey(_lastAttack))
+ {
+ weight.remove(_lastAttack);
+
+ for (Class> c : _preferredCombos.get(_lastAttack))
+ {
+ if (weight.containsKey(c))
+ {
+ weight.put((Class extends BossAbility>)c, weight.get(c) * 4);
+ }
+ }
+ }
+
+ for (BossAbility ability : _currentAbilities)
+ {
+ weight.remove(ability.getClass());
+ }
+
+ BossAbility ability = null;
+
+ if (!weight.isEmpty())
+ {
+ int i = 0;
+
+ for (Integer entry : weight.values())
+ {
+ i += entry;
+ }
+
+ for (int a = 0; a < 10; a++)
+ {
+ int luckyNumber = UtilMath.r(i);
+
+ for (Entry>, Integer> entry : weight.entrySet())
+ {
+ luckyNumber -= entry.getValue();
+
+ if (luckyNumber <= 0)
+ {
+ try
+ {
+ ability = entry.getKey().getConstructor(GolemCreature.class).newInstance(this);
+
+ if (ability.getTarget() == null)
+ {
+ ability = null;
+ }
+ else
+ {
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (ability != null && ability.getTarget() != null)
+ {
+ _lastAttack = (Class extends BossAbility>) ability.getClass();
+
+ if (ability instanceof GolemDeadlyTremor)
+ {
+ _canDeadlyTremor = 225;
+ }
+ else if (ability instanceof GolemSlam)
+ {
+ _lastSlam = System.currentTimeMillis();
+ }
+
+ Bukkit.getPluginManager().registerEvents(ability, UtilServer.getPlugin());
+
+ if (DEBUG_MODE)
+ {
+ System.out.print("Golem boss is using " + ability.getClass().getSimpleName());
+ }
+
+ _currentAbilities.add(ability);
+ }
+
+ _lastAbility = 10;
+ }
+
+ _lastAttack = null;
+ }
+
+ boolean canMove = true;
+
+ for (BossAbility ability : _currentAbilities)
+ {
+ try
+ {
+ ability.tick();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(); //Keeps the boss from getting stuck if one of the moves throws an error in progression
+ }
+
+ if (!ability.canMove())
+ {
+ canMove = false;
+ }
+ }
+
+ if (canMove)
+ {
+ Player target = null;
+ double dist = 0;
+
+ for (Player player : UtilPlayer.getNearby(getEntity().getLocation(), 50, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(getEntity().getLocation());
+
+ if (d > 1.5 && (d < 7 || d > 15) && (target == null || (d < 50 && dist > d)))
+ {
+ target = player;
+ dist = d;
+ }
+ }
+
+ Vector vec = null;
+ boolean superWalk = false;
+
+ if (target != null)
+ {
+ vec = target.getLocation().subtract(getEntity().getLocation()).toVector();
+ vec.setY(getEntity().getLocation().getY());
+
+ double len = vec.length();
+
+ vec.setX(vec.getX() * (UtilMath.random.nextDouble() / 3D));
+ vec.setZ(vec.getZ() * (UtilMath.random.nextDouble() / 3D));
+
+ vec.multiply(len);
+
+ if (target != null && dist < 8)
+ {
+ vec.multiply(-1);
+ superWalk = true;
+ }
+
+ if (!UtilAlg.HasSight(getEntity().getLocation(),
+ getEntity().getLocation().add(vec.clone().normalize().multiply(2))))
+ {
+ _reverseWalk = System.currentTimeMillis();
+ }
+
+ if (!UtilTime.elapsed(_reverseWalk, 4000))
+ {
+ vec.multiply(-1);
+ }
+
+ }
+ else if (!UtilTime.elapsed(_lastWalked, 7000))
+ {
+ vec = _afkWalk;
+ }
+ else if (UtilTime.elapsed(_lastWalked, 12000))
+ {
+ _afkWalk = new Vector();
+
+ for (int i = 0; i < 10; i++)
+ {
+ Vector vector = new Vector(UtilMath.r(20) - 10, 0, UtilMath.r(20) - 10);
+
+ if (UtilAlg.HasSight(getEntity().getLocation(),
+ getEntity().getLocation().add(vector.clone().normalize().multiply(2))))
+ {
+ vec = _afkWalk = vector;
+ break;
+ }
+ }
+
+ _lastWalked = System.currentTimeMillis();
+ }
+
+ if (vec != null)
+ {
+ {
+ UtilEnt.CreatureMoveFast(getEntity(), getEntity().getLocation().add(vec),
+ (target != null ? 1.8F : 1.1F) + (superWalk ? 0.4F : 0));
+ }
+ }
+
+ _standing = getEntity().getLocation();
+ }
+ else
+ {
+ Location l = getEntity().getLocation();
+
+ _standing.setYaw(l.getYaw());
+ _standing.setPitch(l.getPitch());
+ _standing.setY(l.getY());
+
+ getEntity().teleport(_standing);
+ }
+ }
+
+ private List getPlayers(final Map map, double maxDist)
+ {
+ List list = new ArrayList();
+
+ for (Player p : map.keySet())
+ {
+ if (map.get(p) <= maxDist)
+ {
+ list.add(p);
+ }
+ }
+
+ Collections.sort(list, (o1, o2) ->
+ {
+ return Double.compare(map.get(o2), map.get(o1));
+ });
+
+ return list;
+ }
+
+ @EventHandler
+ public void onGolemDamage(CustomDamageEvent event)
+ {
+ if (event.GetDamageeEntity().equals(getEntity()))
+ {
+ event.AddKnockback("Heavy Golem", 0.3);
+ }
+ }
+
+ @EventHandler
+ public void onRangedAttack(CustomDamageEvent event)
+ {
+ if (event.GetDamageeEntity().equals(getEntity()))
+ {
+ if (event.GetDamageePlayer() != null)
+ {
+ if (event.GetProjectile() != null && event.GetProjectile() instanceof Arrow)
+ {
+ if (new Random().nextDouble() <= .5)
+ {
+ event.SetCancelled("Iron Skin Reflection");
+ getEntity().getWorld().playSound(getEntity().getLocation(), Sound.ZOMBIE_METAL, 0.5f, 1.6f);
+ return;
+ }
+ }
+
+ double dist = event.GetDamageePlayer().getLocation().distance(getEntity().getLocation());
+
+ double maxRange = _usedFinalAttack ? 20 : 45;
+
+ double modifier = (maxRange - dist) / maxRange;
+
+ if (modifier > 0)
+ {
+ event.AddMod("Ranged Resistance", 1 - modifier);
+ }
+ else
+ {
+ event.SetCancelled("Range too far");
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dieCustom()
+ {
+ endAbility();
+ }
+
+ private void endAbility()
+ {
+ for (BossAbility ability : _currentAbilities)
+ {
+ ability.setFinished();
+ HandlerList.unregisterAll(ability);
+ }
+
+ _currentAbilities.clear();
+ }
+
+ @Override
+ public void setHealth(double health)
+ {
+ _canDeadlyTremor -= getHealth() - health;
+ super.setHealth(health);
+ if (getHealth() <= 100 && !_usedFinalAttack)
+ {
+ endAbility();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/BlockHailBlock.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/BlockHailBlock.java
new file mode 100644
index 000000000..d837321c9
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/BlockHailBlock.java
@@ -0,0 +1,88 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.IronGolem;
+
+import mineplex.core.common.util.UtilEnt;
+import net.minecraft.server.v1_8_R3.DataWatcher;
+import net.minecraft.server.v1_8_R3.Entity;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayOutAttachEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving;
+
+public class BlockHailBlock
+{
+ private int _block = UtilEnt.getNewEntityId();
+ private int _silverfish = UtilEnt.getNewEntityId();
+ private Location _location;
+ private Material _mat;
+
+ public BlockHailBlock(Location loc, Material mat)
+ {
+ _location = loc;
+ _mat = mat;
+ }
+
+ public PacketPlayOutEntityDestroy getDestroyPacket()
+ {
+ return new PacketPlayOutEntityDestroy(new int[]
+ {
+ _silverfish, _block
+ });
+ }
+
+ public Location getLocation()
+ {
+ return _location;
+ }
+
+ public Material getMaterial()
+ {
+ return _mat;
+ }
+
+ @SuppressWarnings("deprecation")
+ public Packet>[] getSpawnPackets(IronGolem entity)
+ {
+ Packet>[] packets = new Packet[3];
+
+ PacketPlayOutSpawnEntityLiving packet1 = new PacketPlayOutSpawnEntityLiving();
+
+ DataWatcher watcher = new DataWatcher(null);
+ watcher.a(0, (byte) 32, Entity.META_ENTITYDATA, (byte) 0);
+ watcher.a(1, 0, Entity.META_AIR, 0);
+
+ packet1.a = _silverfish;
+ packet1.b = EntityType.SILVERFISH.getTypeId();
+ packet1.c = (int) Math.floor(_location.getX() * 32);
+ packet1.d = (int) Math.floor(_location.getY() * 32);
+ packet1.e = (int) Math.floor(_location.getZ() * 32);
+ packet1.l = watcher;
+
+ packets[0] = packet1;
+
+ PacketPlayOutSpawnEntity packet2 = new PacketPlayOutSpawnEntity(((CraftEntity) entity).getHandle(), 70, _mat.getId());
+
+ packet2.a = _block;
+
+ packet2.b = (int) Math.floor(_location.getX() * 32);
+ packet2.c = (int) Math.floor(entity.getLocation().getY() * 32);
+ packet2.d = (int) Math.floor(_location.getZ() * 32);
+
+ packets[1] = packet2;
+
+ PacketPlayOutAttachEntity packet3 = new PacketPlayOutAttachEntity();
+
+ packet3.b = _block;
+ packet3.c = _silverfish;
+
+ packets[2] = packet3;
+
+ return packets;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockHail.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockHail.java
new file mode 100644
index 000000000..99c437774
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockHail.java
@@ -0,0 +1,475 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.IronGolem;
+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.util.Vector;
+
+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.UtilPlayer;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.common.util.UtilShapes;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.AxisAlignedBB;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+import net.minecraft.server.v1_8_R3.MathHelper;
+import net.minecraft.server.v1_8_R3.MovingObjectPosition;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
+import net.minecraft.server.v1_8_R3.Vec3D;
+
+public class GolemBlockHail extends BossAbility
+{
+ private int _currentBlock;
+ private int _currentLevel;
+ private List _fallingBlocks = new ArrayList<>();
+ private Map> _floatingBlocks = new HashMap<>();
+ private Map _blocks = new HashMap<>();
+ private int _levelToReach;
+ private boolean _spawned;
+ private List _spawnLocs = new ArrayList<>();
+ private Player _target;
+ private Location _center;
+ private int _ticks;
+
+ public GolemBlockHail(GolemCreature creature)
+ {
+ super(creature);
+
+ _center = getLocation();
+
+ if (creature.getHealthPercent() > 0.75)
+ {
+ _levelToReach = 1;
+ }
+ else if (creature.getHealthPercent() > 0.5)
+ {
+ _levelToReach = 2;
+ }
+ else
+ {
+ _levelToReach = 3;
+ }
+
+ _target = getTarget();
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ Player target = null;
+ double dist = 0;
+
+ if (inProgress())
+ {
+ for (Player player : UtilPlayer.getNearby(_center, 40, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ if (target != null && _blocks.containsKey(player.getName()) && _blocks.get(player.getName()) > 8)
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(_center);
+
+ if (target == null || dist > d)
+ {
+ target = player;
+ dist = d;
+ }
+ }
+ }
+
+ return target;
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return _spawned && _floatingBlocks.isEmpty();
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _target == null || !_target.isValid() || ((_fallingBlocks.isEmpty() && _spawned) && _ticks >= 8 * 9)
+ || _center.distance(_target.getLocation()) > 100;
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ Iterator fallingIterator = _fallingBlocks.iterator();
+
+ while (fallingIterator.hasNext())
+ {
+ FallingBlock cur = fallingIterator.next();
+
+ if (cur.isDead() || !cur.isValid() || cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ fallingIterator.remove();
+
+ Block block = cur.getLocation().getBlock();
+ block.setTypeIdAndData(0, (byte) 0, true);
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ // Expire
+ if (cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ cur.remove();
+ continue;
+ }
+
+ cur.remove();
+ continue;
+ }
+
+ double distanceToEntity = 0.0D;
+ LivingEntity victim = null;
+
+ net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity) cur).getHandle();
+ Vec3D vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ Vec3D vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY,
+ nmsEntity.locZ + nmsEntity.motZ);
+
+ MovingObjectPosition finalObjectPosition = nmsEntity.world.rayTrace(vec3d, vec3d1, false, true, false);
+ vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ if (finalObjectPosition != null)
+ {
+ vec3d1 = new Vec3D(finalObjectPosition.pos.a, finalObjectPosition.pos.b, finalObjectPosition.pos.c);
+ }
+
+ for (Object entity : ((CraftWorld) cur.getWorld()).getHandle().getEntities(((CraftEntity) cur).getHandle(),
+ ((CraftEntity) cur).getHandle().getBoundingBox().a(((CraftEntity) cur).getHandle().motX,
+ ((CraftEntity) cur).getHandle().motY, ((CraftEntity) cur).getHandle().motZ).grow(2, 2, 2)))
+ {
+ Entity bukkitEntity = ((net.minecraft.server.v1_8_R3.Entity) entity).getBukkitEntity();
+
+ if (bukkitEntity instanceof LivingEntity)
+ {
+ LivingEntity ent = (LivingEntity) bukkitEntity;
+
+ // Avoid Self
+ if (ent.equals(getEntity()))
+ continue;
+
+ // Creative or Spec
+ if (ent instanceof Player)
+ if (((Player) ent).getGameMode() == GameMode.CREATIVE || UtilPlayer.isSpectator(ent))
+ continue;
+
+ // float f1 = (float)(nmsEntity.boundingBox.a() * 0.6f);
+ AxisAlignedBB axisalignedbb1 = ((CraftEntity) ent).getHandle().getBoundingBox().grow(1F, 1F, 1F);
+ MovingObjectPosition entityCollisionPosition = axisalignedbb1.a(vec3d, vec3d1);
+
+ if (entityCollisionPosition != null)
+ {
+ double d1 = vec3d.distanceSquared(entityCollisionPosition.pos);
+ if ((d1 < distanceToEntity) || (distanceToEntity == 0.0D))
+ {
+ victim = ent;
+ distanceToEntity = d1;
+ }
+ }
+ }
+ }
+
+ if (victim != null)
+ {
+ cur.getWorld().playEffect(victim.getEyeLocation().subtract(0, 0.5, 0), Effect.STEP_SOUND, cur.getBlockId());
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) victim, getEntity(), null,
+ DamageCause.CONTACT, 10 * getBoss().getDifficulty(), true, true, false, "Iron Wizard Block Hail",
+ "Iron Wizard Block Hail");
+ }
+
+ if (victim instanceof Player)
+ {
+ getBoss().getEvent().getCondition().Factory().Slow("Iron Wizard Block Hail", (LivingEntity) victim,
+ getEntity(), 3, 2, false, false, false, false);
+ }
+
+ fallingIterator.remove();
+ cur.remove();
+ }
+ else if (finalObjectPosition != null)
+ {
+ Block block = cur.getWorld().getBlockAt(((int) finalObjectPosition.pos.a), ((int) finalObjectPosition.pos.b), ((int) finalObjectPosition.pos.c));
+
+ if (!UtilBlock.airFoliage(block) && !block.isLiquid())
+ {
+ nmsEntity.motX = ((float) (finalObjectPosition.pos.a - nmsEntity.locX));
+ nmsEntity.motY = ((float) (finalObjectPosition.pos.b - nmsEntity.locY));
+ nmsEntity.motZ = ((float) (finalObjectPosition.pos.c - nmsEntity.locZ));
+ float f2 = MathHelper.sqrt(
+ nmsEntity.motX * nmsEntity.motX + nmsEntity.motY * nmsEntity.motY + nmsEntity.motZ * nmsEntity.motZ);
+ nmsEntity.locX -= nmsEntity.motX / f2 * 0.0500000007450581D;
+ nmsEntity.locY -= nmsEntity.motY / f2 * 0.0500000007450581D;
+ nmsEntity.locZ -= nmsEntity.motZ / f2 * 0.0500000007450581D;
+
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ fallingIterator.remove();
+ cur.remove();
+ }
+ }
+ else
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ cur.getLocation().add(0, 0.5, 0), 0.3F, 0.3F, 0.3F, 0, 2, UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (List floatingBlocks : _floatingBlocks.values())
+ {
+ for (BlockHailBlock falling : floatingBlocks)
+ {
+ PacketPlayOutEntityDestroy packet = falling.getDestroyPacket();
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+ }
+ }
+
+ for (FallingBlock block : _fallingBlocks)
+ {
+ block.remove();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ if (inProgress())
+ {
+ for (Player player : UtilPlayer.getNearby(_center, 5, true))
+ {
+ Location loc = player.getLocation();
+
+ if (Math.abs(loc.getY() - (_center.getY() + 1)) <= 1)
+ {
+ loc.setY(_center.getY());
+
+ if (loc.distance(_center) < 2.8 + (_currentLevel * 0.75))
+ {
+ if (canDamage(player))
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent(player, getEntity(), null,
+ DamageCause.CONTACT, 10 * getBoss().getDifficulty(), true, true, false,
+ "Iron Wizard Protection", "Iron Wizard Protection");
+
+ loc.getWorld().playEffect(player.getLocation(), Effect.STEP_SOUND, Material.OBSIDIAN.getId());
+ loc.getWorld().playEffect(player.getEyeLocation(), Effect.STEP_SOUND, Material.OBSIDIAN.getId());
+ }
+ }
+ }
+ }
+ }
+
+ if (!_spawned)
+ {
+ if (_currentBlock >= _spawnLocs.size())
+ {
+
+ if (_currentLevel + 1 <= _levelToReach)
+ {
+ _currentLevel++;
+ _currentBlock = 0;
+
+ _spawnLocs = UtilShapes.getDistancedCircle(_center.clone().add(0, 2.8 + (_currentLevel * 0.75), 0), 1.3,
+ 1 + (_currentLevel * 1.3));
+
+ for (int i = UtilMath.r(_spawnLocs.size()); i > 0; i--)
+ {
+ _spawnLocs.add(_spawnLocs.remove(0));
+ }
+ }
+ }
+
+ if (_currentBlock < _spawnLocs.size())
+ {
+ if (_ticks % 2 == 0)
+ {
+ IronGolem entity = getEntity();
+
+ Location loc = _spawnLocs.get(_currentBlock++);
+
+ List floatingBlocks = new ArrayList<>();
+
+ if (_floatingBlocks.containsKey(_currentLevel))
+ {
+ floatingBlocks = _floatingBlocks.get(_currentLevel);
+ }
+ else
+ {
+ _floatingBlocks.put(_currentLevel, floatingBlocks);
+ }
+
+ if (loc.getBlock().getType() == Material.AIR && UtilAlg.HasSight(entity.getLocation(), loc))
+ {
+
+ BlockHailBlock floating = new BlockHailBlock(loc, Material.STONE);
+ UtilEnt.CreatureLook(entity, _target);
+
+ floatingBlocks.add(floating);
+
+ Packet>[] packets = floating.getSpawnPackets(entity);
+
+ for (Player player : UtilPlayer.getNearby(loc, 100))
+ {
+ UtilPlayer.sendPacket(player, packets);
+ }
+
+ entity.getWorld().playSound(entity.getLocation(), Sound.DIG_GRASS, 3, 0.9F);
+ }
+
+ if (_floatingBlocks.size() % 2 == 0)
+ {
+ Collections.reverse(floatingBlocks);
+ }
+ }
+ }
+ else
+ {
+ _spawned = true;
+ _ticks = -20;
+ }
+ }
+ else if (_ticks > 0 && _ticks % 2 == 0 && !_floatingBlocks.isEmpty())
+ {
+ IronGolem entity = getEntity();
+
+ if (_ticks % 16 == 0)
+ {
+ _target = getTarget();
+
+ if (_target == null)
+ return;
+ }
+
+ EntityIronGolem golem = ((CraftIronGolem) entity).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+ UtilEnt.CreatureLook(entity, _target);
+
+ BlockHailBlock floatingBlock = null;
+
+ for (int i = 1; i <= _currentLevel; i++)
+ {
+ if (_floatingBlocks.containsKey(i) && !_floatingBlocks.get(i).isEmpty())
+ {
+ floatingBlock = _floatingBlocks.get(i).remove(0);
+
+ if (_floatingBlocks.get(i).isEmpty())
+ {
+ _floatingBlocks.remove(i);
+ }
+
+ break;
+ }
+ }
+
+ PacketPlayOutEntityDestroy packet = floatingBlock.getDestroyPacket();
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+
+ Location loc = floatingBlock.getLocation();
+
+ FallingBlock b = loc.getWorld().spawnFallingBlock(loc, floatingBlock.getMaterial(), (byte) 0);
+ b.setDropItem(false);
+
+ Vector vec = UtilAlg.calculateVelocity(loc.toVector(),
+ _target.getLocation().toVector().add(new Vector(UtilMath.r(6 + (_currentLevel * 2)) - (2 + _currentLevel), 0,
+ UtilMath.r(6 + (_currentLevel * 2)) - (2 + _currentLevel))),
+ 6);
+
+ b.setVelocity(vec);
+
+ _fallingBlocks.add(b);
+
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 3, 0.9F);
+
+ _blocks.put(_target.getName(), _blocks.containsKey(_target.getName()) ? _blocks.get(_target.getName()) + 1 : 1);
+ }
+
+ List points = new ArrayList<>();
+
+ for (int i = _currentLevel; i <= _currentLevel; i++)
+ {
+ points.addAll(UtilShapes.getDistancedCircle(_center.clone().add(0, 3.3 + (i * 0.75), 0), 0.3, 1 + (i * 1.3)));
+ }
+
+ for (int i = 0; i < points.size(); i++)
+ {
+ if (_spawned || i < _ticks)
+ {
+ Location loc = points.get(i);
+
+ UtilParticle.PlayParticle(
+ ParticleType.BLOCK_DUST.getParticle(_spawned && i < _ticks ? Material.STONE : Material.DIRT, 0), loc, 0,
+ 0, 0, 0, 0, UtilParticle.ViewDist.LONG, UtilServer.getPlayers());
+ }
+ }
+
+ _ticks++;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return !_spawned || !_floatingBlocks.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockShot.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockShot.java
new file mode 100644
index 000000000..4f652b4a8
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemBlockShot.java
@@ -0,0 +1,442 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+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;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+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.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.IronGolem;
+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.util.Vector;
+
+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.UtilPlayer;
+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.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.AxisAlignedBB;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+import net.minecraft.server.v1_8_R3.MathHelper;
+import net.minecraft.server.v1_8_R3.MovingObjectPosition;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityVelocity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
+import net.minecraft.server.v1_8_R3.Vec3D;
+
+public class GolemBlockShot extends BossAbility
+{
+ private Map _blockLoc = new HashMap<>();
+ private Map _blockType = new HashMap<>();
+ private List _current = new ArrayList<>();
+ private Map _preshoot = new HashMap<>();
+ private Player _target;
+ private Map _targetBlock = new HashMap<>();
+ private Map _shotAt = new HashMap<>();
+ private int _thrown;
+ private int _tick;
+ private int _toThrow;
+
+ public GolemBlockShot(GolemCreature creature)
+ {
+ super(creature);
+
+ if (creature.getHealthPercent() > 0.75)
+ {
+ _toThrow = 3;
+ }
+ else if (creature.getHealthPercent() > 0.5)
+ {
+ _toThrow = 6;
+ }
+ else
+ {
+ _toThrow = 9;
+ }
+
+ _target = getTarget();
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return _current.isEmpty() && _thrown == _toThrow;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ Player target = null;
+ double dist = 0;
+
+ Location loc1 = getLocation();
+ Location loc2 = loc1.clone().add(loc1.getDirection().setY(0).normalize());
+
+ List players = UtilPlayer.getNearby(getLocation(), 40, true);
+
+ for (Player player : players)
+ {
+ if (_shotAt.containsKey(player.getUniqueId()) && _shotAt.get(player.getUniqueId()) >= 3)
+ {
+ continue;
+ }
+
+ double dist1 = player.getLocation().distance(loc1);
+ double dist2 = player.getLocation().distance(loc2);
+
+ double dist3 = dist1 - dist2;
+
+ if (dist3 < 0.6 || dist1 > 30 || (target != null && dist3 < dist))
+ {
+ continue;
+ }
+
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ target = player;
+ dist = dist3;
+ }
+
+ return target;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _current.isEmpty() && _preshoot.isEmpty() && (_target == null || _thrown >= _toThrow);
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ Iterator fallingIterator = _current.iterator();
+
+ while (fallingIterator.hasNext())
+ {
+ FallingBlock cur = fallingIterator.next();
+
+ if (cur.isDead() || !cur.isValid() || cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ fallingIterator.remove();
+
+ Block block = cur.getLocation().getBlock();
+ block.setTypeIdAndData(0, (byte) 0, true);
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ // Expire
+ if (cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ cur.remove();
+ continue;
+ }
+
+ cur.remove();
+ continue;
+ }
+
+ double distanceToEntity = 0.0D;
+ LivingEntity victim = null;
+
+ net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity) cur).getHandle();
+ Vec3D vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ Vec3D vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY,
+ nmsEntity.locZ + nmsEntity.motZ);
+
+ MovingObjectPosition finalObjectPosition = nmsEntity.world.rayTrace(vec3d, vec3d1, false, true, false);
+ vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ if (finalObjectPosition != null)
+ {
+ vec3d1 = new Vec3D(finalObjectPosition.pos.a, finalObjectPosition.pos.b, finalObjectPosition.pos.c);
+ }
+
+ for (Object entity : ((CraftWorld) cur.getWorld()).getHandle().getEntities(((CraftEntity) cur).getHandle(),
+ ((CraftEntity) cur).getHandle().getBoundingBox().a(((CraftEntity) cur).getHandle().motX,
+ ((CraftEntity) cur).getHandle().motY, ((CraftEntity) cur).getHandle().motZ).grow(2, 2, 2)))
+ {
+ Entity bukkitEntity = ((net.minecraft.server.v1_8_R3.Entity) entity).getBukkitEntity();
+
+ if (bukkitEntity instanceof LivingEntity)
+ {
+ LivingEntity ent = (LivingEntity) bukkitEntity;
+
+ // Avoid Self
+ if (ent.equals(getEntity()))
+ continue;
+
+ // Creative or Spec
+ if (ent instanceof Player)
+ if (((Player) ent).getGameMode() == GameMode.CREATIVE || UtilPlayer.isSpectator(ent))
+ continue;
+
+ // float f1 = (float)(nmsEntity.boundingBox.a() * 0.6f);
+ AxisAlignedBB axisalignedbb1 = ((CraftEntity) ent).getHandle().getBoundingBox().grow(1F, 1F, 1F);
+ MovingObjectPosition entityCollisionPosition = axisalignedbb1.a(vec3d, vec3d1);
+
+ if (entityCollisionPosition != null)
+ {
+ double d1 = vec3d.distanceSquared(entityCollisionPosition.pos);
+ if ((d1 < distanceToEntity) || (distanceToEntity == 0.0D))
+ {
+ victim = ent;
+ distanceToEntity = d1;
+ }
+ }
+ }
+ }
+
+ if (victim != null)
+ {
+ cur.getWorld().playEffect(victim.getEyeLocation().subtract(0, 0.5, 0), Effect.STEP_SOUND, cur.getBlockId());
+
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) victim, getEntity(), null,
+ DamageCause.CONTACT, 10 * getBoss().getDifficulty(), true, true, false, "Iron Wizard Block Shot",
+ "Iron Wizard Block Shot");
+
+ cur.remove();
+ fallingIterator.remove();
+
+ Vector vec = UtilAlg.getTrajectory(getEntity(), victim);
+ vec.setY(0).normalize();
+
+ double strength = 1;
+
+ if (!(victim instanceof Player) || !((Player) victim).isBlocking())
+ {
+ strength = 1.3;
+ }
+
+ UtilAction.velocity(victim, vec, strength, true, 0, 0.2, 1, true);
+ }
+ else if (finalObjectPosition != null)
+ {
+ Block block = cur.getWorld().getBlockAt(((int) finalObjectPosition.pos.a), ((int) finalObjectPosition.pos.b), ((int) finalObjectPosition.pos.c));
+
+ if (!UtilBlock.airFoliage(block) && !block.isLiquid())
+ {
+ nmsEntity.motX = ((float) (finalObjectPosition.pos.a - nmsEntity.locX));
+ nmsEntity.motY = ((float) (finalObjectPosition.pos.b - nmsEntity.locY));
+ nmsEntity.motZ = ((float) (finalObjectPosition.pos.c - nmsEntity.locZ));
+ float f2 = MathHelper.sqrt(
+ nmsEntity.motX * nmsEntity.motX + nmsEntity.motY * nmsEntity.motY + nmsEntity.motZ * nmsEntity.motZ);
+ nmsEntity.locX -= nmsEntity.motX / f2 * 0.0500000007450581D;
+ nmsEntity.locY -= nmsEntity.motY / f2 * 0.0500000007450581D;
+ nmsEntity.locZ -= nmsEntity.motZ / f2 * 0.0500000007450581D;
+
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+ cur.remove();
+ fallingIterator.remove();
+ }
+ }
+ else
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ cur.getLocation().add(0, 0.5, 0), 0.3F, 0.3F, 0.3F, 0, 2, UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (FallingBlock falling : _current)
+ {
+ falling.remove();
+ }
+
+ int[] ids = new int[_preshoot.size()];
+
+ int a = 0;
+ for (int id : _preshoot.keySet())
+ {
+ ids[a++] = id;
+ }
+
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ids);
+
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ if (_target == null || _target.getLocation().distance(getLocation()) > 30 || !_target.hasLineOfSight(getEntity()))
+ {
+ _target = getTarget();
+ }
+
+ Entity entity = getEntity();
+
+ if (_tick++ % 16 == 0 && _target != null && _thrown < _toThrow)
+ {
+ _thrown++;
+
+ UtilEnt.CreatureLook(entity, _target);
+ EntityIronGolem golem = ((CraftIronGolem) entity).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 2, 1);
+
+ Location loc = entity.getLocation();
+ loc.setYaw(loc.getYaw() + (UtilMath.r(150) - 75));
+ loc.add(loc.getDirection().setY(0).normalize());
+
+ Block block = loc.getBlock();
+
+ if (block.getType() == Material.AIR)
+ {
+ block = block.getRelative(BlockFace.DOWN);
+ }
+
+ Material mat = block.getType();
+
+ if (!UtilBlock.solid(block))
+ {
+ mat = Material.STONE;
+ }
+
+ int id = UtilEnt.getNewEntityId();
+
+ _preshoot.put(id, System.currentTimeMillis());
+ _blockType.put(id, mat);
+ _blockLoc.put(id, loc.clone().add(0, 0.6, 0));
+ _targetBlock.put(id, _target);
+
+ PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(((CraftEntity) entity).getHandle(), 70, mat.getId());
+
+ packet.a = id;
+
+ packet.b = (int) Math.floor(loc.getX() * 32);
+ packet.c = (int) Math.floor(loc.getY() * 32);
+ packet.d = (int) Math.floor(loc.getZ() * 32);
+
+ packet.g = (int) ((0.45) * 8000);
+
+ PacketPlayOutEntityVelocity packet2 = new PacketPlayOutEntityVelocity(id, 0, 0.45D, 0);
+
+ for (Player player : UtilPlayer.getNearby(loc, 70))
+ {
+ UtilPlayer.sendPacket(player, packet, packet2);
+ }
+
+ _shotAt.put(_target.getUniqueId(),
+ (_shotAt.containsKey(_target.getUniqueId()) ? _shotAt.get(_target.getUniqueId()) : 0) + 1);
+
+ _target = getTarget();
+ }
+ else
+ {
+ Iterator> itel = _preshoot.entrySet().iterator();
+
+ while (itel.hasNext())
+ {
+ Entry entry = itel.next();
+
+ if (UtilTime.elapsed(entry.getValue(), 920))
+ {
+ itel.remove();
+
+ int id = entry.getKey();
+
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(new int[]
+ {
+ id
+ });
+
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+
+ Location loc = _blockLoc.get(id);
+ FallingBlock falling = loc.getWorld().spawnFallingBlock(loc, _blockType.get(id), (byte) 0);
+ falling.setDropItem(false);
+
+ _current.add(falling);
+
+ Player target = _targetBlock.get(id);
+
+ UtilEnt.CreatureLook(entity, target);
+ EntityIronGolem golem = ((CraftIronGolem) entity).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 2, 1.2F);
+ entity.getWorld().playEffect(falling.getLocation(), Effect.STEP_SOUND, falling.getBlockId());
+
+ Location l = falling.getLocation();
+ l.setY(entity.getLocation().getY());
+
+ Location loc1 = target.getEyeLocation();
+
+ if (loc1.getY() - l.getY() > 1)
+ {
+ loc1.setY(l.getY() + 1);
+ }
+
+ int dist = (int) Math.ceil(loc1.toVector().setY(0).distance(l.toVector().setY(0)));
+
+ Vector vector = UtilAlg.calculateVelocity(l.toVector(), loc1.toVector(), dist / 13);
+
+ falling.setVelocity(vector);
+ }
+ }
+ }
+
+ if (_thrown >= 3 && !UtilPlayer.getNearby(getLocation(), 10, true).isEmpty())
+ {
+ _thrown = 99;
+ }
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return _thrown < _toThrow || !_current.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemCaveIn.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemCaveIn.java
new file mode 100644
index 000000000..5656844ad
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemCaveIn.java
@@ -0,0 +1,336 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.IronGolem;
+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.util.Vector;
+
+import mineplex.core.common.util.UtilAction;
+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.UtilPlayer;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.common.util.UtilShapes;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.AxisAlignedBB;
+import net.minecraft.server.v1_8_R3.MathHelper;
+import net.minecraft.server.v1_8_R3.MovingObjectPosition;
+import net.minecraft.server.v1_8_R3.Vec3D;
+
+public class GolemCaveIn extends BossAbility
+{
+ private List _blocks = new ArrayList<>();
+ private List _fallingBlocks = new ArrayList<>();
+ private int _tick;
+
+ public GolemCaveIn(GolemCreature creature)
+ {
+ super(creature);
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return false;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ if (getTarget(4) == null)
+ {
+ return getTarget(40);
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _tick > 60 && _fallingBlocks.isEmpty();
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ Iterator fallingIterator = _fallingBlocks.iterator();
+
+ while (fallingIterator.hasNext())
+ {
+ FallingBlock cur = fallingIterator.next();
+
+ if (cur.isDead() || !cur.isValid() || cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ fallingIterator.remove();
+
+ Block block = cur.getLocation().getBlock();
+ block.setTypeIdAndData(0, (byte) 0, true);
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ // Expire
+ if (cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ cur.remove();
+ continue;
+ }
+
+ cur.remove();
+ continue;
+ }
+
+ double distanceToEntity = 0.0D;
+ LivingEntity victim = null;
+
+ net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity) cur).getHandle();
+ Vec3D vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ Vec3D vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY,
+ nmsEntity.locZ + nmsEntity.motZ);
+
+ MovingObjectPosition finalObjectPosition = nmsEntity.world.rayTrace(vec3d, vec3d1, false, true, false);
+ vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ if (finalObjectPosition != null)
+ {
+ vec3d1 = new Vec3D(finalObjectPosition.pos.a, finalObjectPosition.pos.b, finalObjectPosition.pos.c);
+ }
+
+ for (Object entity : ((CraftWorld) cur.getWorld()).getHandle().getEntities(((CraftEntity) cur).getHandle(),
+ ((CraftEntity) cur).getHandle().getBoundingBox().a(((CraftEntity) cur).getHandle().motX,
+ ((CraftEntity) cur).getHandle().motY, ((CraftEntity) cur).getHandle().motZ).grow(2, 2, 2)))
+ {
+ Entity bukkitEntity = ((net.minecraft.server.v1_8_R3.Entity) entity).getBukkitEntity();
+
+ if (bukkitEntity instanceof LivingEntity)
+ {
+ LivingEntity ent = (LivingEntity) bukkitEntity;
+
+ // Avoid Self
+ if (ent.equals(getEntity()))
+ continue;
+
+ // Creative or Spec
+ if (ent instanceof Player)
+ if (((Player) ent).getGameMode() == GameMode.CREATIVE || UtilPlayer.isSpectator(ent))
+ continue;
+
+ // float f1 = (float)(nmsEntity.boundingBox.a() * 0.6f);
+ AxisAlignedBB axisalignedbb1 = ((CraftEntity) ent).getHandle().getBoundingBox().grow(1F, 1F, 1F);
+ MovingObjectPosition entityCollisionPosition = axisalignedbb1.a(vec3d, vec3d1);
+
+ if (entityCollisionPosition != null)
+ {
+ double d1 = vec3d.distanceSquared(entityCollisionPosition.pos);
+ if ((d1 < distanceToEntity) || (distanceToEntity == 0.0D))
+ {
+ victim = ent;
+ distanceToEntity = d1;
+ }
+ }
+ }
+ }
+
+ if (victim != null)
+ {
+ cur.getWorld().playEffect(victim.getEyeLocation().subtract(0, 0.5, 0), Effect.STEP_SOUND, cur.getBlockId());
+
+ if (canDamage(victim))
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) victim, getEntity(), null,
+ DamageCause.CONTACT, 10 * getBoss().getDifficulty(), true, true, false, "Iron Wizard Cave In",
+ "Iron Wizard Cave In");
+ }
+
+ cur.remove();
+ fallingIterator.remove();
+ }
+ else if (finalObjectPosition != null)
+ {
+ Block block = cur.getWorld().getBlockAt(((int) finalObjectPosition.pos.a), ((int) finalObjectPosition.pos.b), ((int) finalObjectPosition.pos.c));
+
+ if (!UtilBlock.airFoliage(block) && !block.isLiquid())
+ {
+ nmsEntity.motX = ((float) (finalObjectPosition.pos.a - nmsEntity.locX));
+ nmsEntity.motY = ((float) (finalObjectPosition.pos.b - nmsEntity.locY));
+ nmsEntity.motZ = ((float) (finalObjectPosition.pos.c - nmsEntity.locZ));
+ float f2 = MathHelper.sqrt(
+ nmsEntity.motX * nmsEntity.motX + nmsEntity.motY * nmsEntity.motY + nmsEntity.motZ * nmsEntity.motZ);
+ nmsEntity.locX -= nmsEntity.motX / f2 * 0.0500000007450581D;
+ nmsEntity.locY -= nmsEntity.motY / f2 * 0.0500000007450581D;
+ nmsEntity.locZ -= nmsEntity.motZ / f2 * 0.0500000007450581D;
+
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+ cur.remove();
+ fallingIterator.remove();
+ }
+ }
+ else
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ cur.getLocation().add(0, 0.5, 0), 0.3F, 0.3F, 0.3F, 0, 2, UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void setFinished()
+ {
+ for (FallingBlock block : _fallingBlocks)
+ {
+ block.remove();
+ }
+
+ for (Block block : _blocks)
+ {
+ block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getTypeId());
+ block.setType(Material.AIR);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ if (_tick++ == 0)
+ {
+ Location l = getLocation();
+
+ List blocks = UtilShapes.getSphereBlocks(l, 3, 3, true);
+
+ for (Location loc : blocks)
+ {
+ if (loc.getBlockY() >= l.getBlockY())
+ {
+ Block b = loc.getBlock();
+
+ if (b.getType() == Material.AIR)
+ {
+ _blocks.add(b);
+
+ loc.setY(l.getY() - 1);
+
+ b.setType(loc.getBlock().getType());
+
+ b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, loc.getBlock().getTypeId());
+ }
+ }
+ }
+ }
+
+ if (_tick % 5 == 0)
+
+ {
+ for (Player player : UtilPlayer.getNearby(getLocation(), 2.5, true))
+ {
+ player.teleport(player.getLocation().add(0, 4, 0));
+ UtilAction.velocity(player, new Vector(UtilMath.r(10) - 5, 3, UtilMath.r(10) - 5).normalize());
+ }
+ }
+
+ if (_tick < 200)
+
+ {
+ Location loc = getLocation();
+ loc.setY(loc.getY() + 4);
+
+ for (int i = 0; i < 30; i++)
+ {
+ loc.setY(loc.getY() + 1);
+ Block b = loc.getBlock();
+
+ if (UtilBlock.solid(b))
+ {
+ break;
+ }
+ }
+
+ if (!UtilBlock.solid(loc.getBlock()))
+ {
+ return;
+ }
+
+ List players = UtilPlayer.getNearby(getLocation(), 50, true);
+
+ for (int i = 0; i < players.size() * 2; i++)
+ {
+ int dist = UtilMath.r(10);
+
+ if (dist < 3)
+ {
+ dist = 2;
+ }
+ else if (dist < 5)
+ {
+ dist = 5;
+ }
+ else
+ {
+ dist = 10;
+ }
+
+ Location l = players.get(UtilMath.r(players.size())).getLocation().add(UtilMath.r(dist * 2) - dist, 0,
+ UtilMath.r(dist * 2) - dist);
+ l.setY(loc.getY());
+
+ Block b = l.getBlock();
+ l.subtract(0, 1, 0);
+
+ if (UtilBlock.solid(b))
+ {
+ if (l.getBlock().getType() == Material.AIR)
+ {
+ if (UtilAlg.HasSight(l, getLocation().add(0, 4, 0)))
+ {
+ FallingBlock block = b.getWorld().spawnFallingBlock(b.getLocation().add(0.5, -1, 0.5), b.getTypeId(),
+ b.getData());
+
+ block.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, block.getBlockId());
+ block.setDropItem(false);
+
+ _fallingBlocks.add(block);
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemDeadlyTremor.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemDeadlyTremor.java
new file mode 100644
index 000000000..d9934e3c9
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemDeadlyTremor.java
@@ -0,0 +1,89 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import org.bukkit.Effect;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilBlock;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilTime;
+import mineplex.core.recharge.Recharge;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+
+public class GolemDeadlyTremor extends BossAbility
+{
+ private static final long ATTACK_DURATION = 10000;
+ private long _start;
+
+ public GolemDeadlyTremor(GolemCreature creature)
+ {
+ super(creature);
+ _start = System.currentTimeMillis();
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return UtilTime.elapsed(_start, ATTACK_DURATION);
+ }
+
+ @Override
+ public void setFinished()
+ {
+ _start = System.currentTimeMillis() - ATTACK_DURATION;
+ }
+
+ @Override
+ public void tick()
+ {
+ for (Player player : UtilPlayer.getInRadius(getLocation(), 30).keySet())
+ {
+ player.playSound(player.getLocation(), Sound.MINECART_BASE, 0.2f, 0.2f);
+
+ if (UtilEnt.isGrounded(player))
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent(player, getBoss().getEntity(), null, DamageCause.CUSTOM, (1 + 2 * Math.random()) * getBoss().getDifficulty(), false, false, false, getBoss().getEntity().getName(), "Deadly Tremor");
+
+ if (Recharge.Instance.use(player, "Deadly Tremor Hit", 400, false, false))
+ {
+ UtilAction.velocity(player, new Vector(Math.random() - 0.5, Math.random() * 0.2, Math.random() - 0.5),
+ Math.random() * 1 + 1, false, 0, 0.1 + Math.random() * 0.2, 2, true);
+ }
+ }
+
+ for (Block block : UtilBlock.getInRadius(player.getLocation(), 5).keySet())
+ {
+ if (Math.random() < 0.98)
+ continue;
+
+ if (!UtilBlock.solid(block))
+ continue;
+
+ if (!UtilBlock.airFoliage(block.getRelative(BlockFace.UP)))
+ continue;
+
+ player.playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemEarthquake.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemEarthquake.java
new file mode 100644
index 000000000..ae4563a0a
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemEarthquake.java
@@ -0,0 +1,168 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilAlg;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilParticle;
+import mineplex.core.common.util.UtilParticle.ParticleType;
+import mineplex.core.common.util.UtilServer;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+
+public class GolemEarthquake extends BossAbility
+{
+ private Location _center;
+ private float _range;
+ private int _tick;
+ private List _damaged = new ArrayList<>();
+ private boolean _earthquake;
+
+ public GolemEarthquake(GolemCreature creature)
+ {
+ super(creature);
+ _center = getLocation();
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return !UtilEnt.isGrounded(getEntity()) && _tick > 1;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ return getTarget(7);
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _range > 19;
+ }
+
+ @Override
+ public void setFinished()
+ {
+ }
+
+ @Override
+ public void tick()
+ {
+ Entity entity = getEntity();
+
+ if (_tick == 0)
+ {
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 4, 0);
+
+ entity.setVelocity(new Vector(0, 1, 0));
+ }
+ else if (!_earthquake)
+ {
+ _earthquake = _tick > 10 && UtilEnt.isGrounded(entity);
+ }
+
+ if (_earthquake)
+ {
+ _range += 0.7;
+
+ for (float range = _range - 2; range <= _range; range++)
+ {
+ if (range <= 0)
+ {
+ continue;
+ }
+
+ for (int x = -1; x <= 1; x++)
+ {
+ for (int z = -1; z <= 1; z++)
+ {
+ if ((x != 0) == (z != 0))
+ {
+ continue;
+ }
+
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.DIRT, 0),
+ _center.clone().add(x * range, 0.1, z * range), (x != 0) ? 0 : (range / 2), 0.1F,
+ (z != 0) ? 0 : (range / 2), 0, (int) (range * 4), UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+ }
+
+ _center.getWorld().playSound(_center, Sound.DIG_STONE, 2, 0.8F);
+
+ HashSet toDamage = new HashSet();
+
+ Location cornerA = _center.clone().add(-_range, -1, -_range);
+ Location cornerB = _center.clone().add(_range, 1, _range);
+ Location cornerA1 = _center.clone().add(-(_range - 1.5), -1, -(_range - 1.5));
+ Location cornerB1 = _center.clone().add(_range - 1.5, 1, _range - 1.5);
+
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ Location pLoc = player.getLocation();
+
+ if (_damaged.contains(player.getUniqueId()))
+ {
+ continue;
+ }
+
+ if (!UtilAlg.inBoundingBox(pLoc, cornerA, cornerB))
+ {
+ continue;
+ }
+
+ if (UtilAlg.inBoundingBox(pLoc, cornerA1, cornerB1))
+ {
+ continue;
+ }
+
+ toDamage.add(player);
+ }
+
+ for (Player player : toDamage)
+ {
+ _damaged.add(player.getUniqueId());
+
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) player, getEntity(), null,
+ DamageCause.CONTACT, 14 * getBoss().getDifficulty(), false, true, false, "Iron Wizard Earthquake",
+ "Iron Wizard Earthquake");
+
+ getBoss().getEvent().getCondition().Factory().Slow("Earthquake", (LivingEntity) player, getEntity(), 3, 1, false,
+ false, false, false);
+
+ // Velocity
+ UtilAction.velocity(player, UtilAlg.getTrajectory2d(getLocation().toVector(), player.getLocation().toVector()),
+ 1.8, true, 0, 0.5, 0.5, true);
+
+ // Condition
+ getBoss().getEvent().getCondition().Factory().Falling("Earthquake", player, getEntity(), 10, false, true);
+ }
+ }
+
+ _tick++;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return !_earthquake;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplodingAura.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplodingAura.java
new file mode 100644
index 000000000..ff9fe2c67
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplodingAura.java
@@ -0,0 +1,400 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+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;
+
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.IronGolem;
+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.util.Vector;
+
+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.UtilPlayer;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.AxisAlignedBB;
+import net.minecraft.server.v1_8_R3.DataWatcher;
+import net.minecraft.server.v1_8_R3.MathHelper;
+import net.minecraft.server.v1_8_R3.MovingObjectPosition;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayOutAttachEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving;
+import net.minecraft.server.v1_8_R3.Vec3D;
+
+public class GolemExplodingAura extends BossAbility
+{
+ private Map _blocks = new HashMap<>();
+ private Map _blocksLoc = new HashMap<>();
+ private List _fallingBlocks = new ArrayList<>();
+ private Map _blockMaterial = new HashMap<>();
+ private int _tick;
+
+ public GolemExplodingAura(GolemCreature creature)
+ {
+ super(creature);
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _tick > 20 * 30 && _blocks.isEmpty() && _fallingBlocks.isEmpty();
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (FallingBlock block : _fallingBlocks)
+ {
+ block.remove();
+ }
+
+ int[] ids = new int[_blocks.size() * 2];
+
+ int i = 0;
+
+ for (Entry id : _blocks.entrySet())
+ {
+ ids[i] = id.getKey();
+ ids[i + 1] = id.getValue();
+
+ i += 2;
+ }
+
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ids);
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ if (_tick < 25 * 25 && getBoss().getHealth() > 30)
+ {
+ double angle = (2 * Math.PI) / UtilMath.random.nextDouble();
+ double x = 1.7 * Math.cos(angle);
+ double z = 1.7 * Math.sin(angle);
+
+ Location loc = getLocation().add(x, 1 + (UtilMath.random.nextDouble() * 1.6), z);
+
+ loc.getWorld().playEffect(loc, Effect.STEP_SOUND, Material.DIRT.getId());
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), 3, true))
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent(player, getEntity(), null, DamageCause.CONTACT,
+ 6 * getBoss().getDifficulty(), true, true, false, "Iron Wizard Protection", "Iron Wizard Protection");
+ UtilAction.velocity(player, UtilAlg.getTrajectory(getEntity(), player), 1, true, 0.3, 0, 0.3, false);
+ }
+ }
+
+ if (_tick < 20 * 30)
+ {
+ int key = UtilEnt.getNewEntityId();
+ int value = UtilEnt.getNewEntityId();
+
+ Location loc = null;
+
+ for (int i = 0; i < 30; i++)
+ {
+ double angle = (2 * Math.PI) / UtilMath.random.nextDouble();
+ double x = 1.7 * Math.cos(angle);
+ double z = 1.7 * Math.sin(angle);
+
+ loc = getLocation().add(x, 1 + (UtilMath.random.nextDouble() * 1.6), z);
+ boolean found = false;
+
+ for (Location l : _blocksLoc.values())
+ {
+ if (l.distance(loc) < 0.3)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ loc = null;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (loc != null)
+ {
+ _blocks.put(key, value);
+ _blocksLoc.put(key, loc);
+ _blockMaterial.put(key, UtilMath.random.nextBoolean() ? Material.DIRT : Material.STONE);
+
+ Packet>[] packets = new Packet[3];
+
+ PacketPlayOutSpawnEntityLiving packet1 = new PacketPlayOutSpawnEntityLiving();
+
+ DataWatcher watcher = new DataWatcher(null);
+ watcher.a(0, (byte) 32, net.minecraft.server.v1_8_R3.Entity.META_ENTITYDATA, (byte) 0);
+ watcher.a(1, 0, net.minecraft.server.v1_8_R3.Entity.META_AIR, 0);
+
+ packet1.a = key;
+ packet1.b = EntityType.SILVERFISH.getTypeId();
+ packet1.c = (int) Math.floor(loc.getX() * 32);
+ packet1.d = (int) Math.floor((loc.getY() - 0.125) * 32);
+ packet1.e = (int) Math.floor(loc.getZ() * 32);
+ packet1.l = watcher;
+
+ packets[0] = packet1;
+
+ PacketPlayOutSpawnEntity packet2 = new PacketPlayOutSpawnEntity(((CraftEntity) getEntity()).getHandle(), 70,
+ _blockMaterial.get(key).getId());
+
+ packet2.a = value;
+
+ packet2.b = (int) Math.floor(loc.getX() * 32);
+ packet2.c = (int) Math.floor(loc.getY() * 32);
+ packet2.d = (int) Math.floor(loc.getZ() * 32);
+
+ packets[1] = packet2;
+
+ PacketPlayOutAttachEntity packet3 = new PacketPlayOutAttachEntity();
+
+ packet3.b = value;
+ packet3.c = key;
+
+ packets[2] = packet3;
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), 70))
+ {
+ UtilPlayer.sendPacket(player, packets);
+ }
+ }
+ }
+
+ if (_tick % 25 == 0)
+ {
+ for (int i = 0; i < 3; i++)
+ getLocation().getWorld().playSound(getLocation(), Sound.DIG_GRASS, 3, 2);
+
+ for (int key : new ArrayList(_blocksLoc.keySet()))
+ {
+
+ PacketPlayOutEntityDestroy destroyPacket = new PacketPlayOutEntityDestroy(new int[]
+ {
+ key, _blocks.remove(key)
+ });
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ UtilPlayer.sendPacket(player, destroyPacket);
+ }
+
+ Location loc = _blocksLoc.remove(key);
+
+ FallingBlock falling = loc.getWorld().spawnFallingBlock(loc, _blockMaterial.remove(key), (byte) 0);
+
+ _fallingBlocks.add(falling);
+
+ Vector vec = UtilAlg.getTrajectory(getLocation().add(0, 1, 0), loc);
+
+ vec.setY(Math.max(0.05, vec.getY()));
+
+ falling.setVelocity(vec);
+
+ loc.getWorld().playEffect(loc, Effect.STEP_SOUND, Material.DIRT.getId());
+ }
+ }
+
+ _tick++;
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ Iterator fallingIterator = _fallingBlocks.iterator();
+
+ while (fallingIterator.hasNext())
+ {
+ FallingBlock cur = fallingIterator.next();
+
+ if (cur.isDead() || !cur.isValid() || cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ fallingIterator.remove();
+
+ Block block = cur.getLocation().getBlock();
+ block.setTypeIdAndData(0, (byte) 0, true);
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ // Expire
+ if (cur.getTicksLived() > 400
+ || !cur.getWorld().isChunkLoaded(cur.getLocation().getBlockX() >> 4, cur.getLocation().getBlockZ() >> 4))
+ {
+ cur.remove();
+ continue;
+ }
+
+ cur.remove();
+ continue;
+ }
+
+ double distanceToEntity = 0.0D;
+ LivingEntity victim = null;
+
+ net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity) cur).getHandle();
+ Vec3D vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ Vec3D vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY,
+ nmsEntity.locZ + nmsEntity.motZ);
+
+ MovingObjectPosition finalObjectPosition = nmsEntity.world.rayTrace(vec3d, vec3d1, false, true, false);
+ vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ if (finalObjectPosition != null)
+ {
+ vec3d1 = new Vec3D(finalObjectPosition.pos.a, finalObjectPosition.pos.b, finalObjectPosition.pos.c);
+ }
+
+ for (Object entity : ((CraftWorld) cur.getWorld()).getHandle().getEntities(((CraftEntity) cur).getHandle(),
+ ((CraftEntity) cur).getHandle().getBoundingBox().a(((CraftEntity) cur).getHandle().motX,
+ ((CraftEntity) cur).getHandle().motY, ((CraftEntity) cur).getHandle().motZ).grow(2, 2, 2)))
+ {
+ Entity bukkitEntity = ((net.minecraft.server.v1_8_R3.Entity) entity).getBukkitEntity();
+
+ if (bukkitEntity instanceof LivingEntity)
+ {
+ LivingEntity ent = (LivingEntity) bukkitEntity;
+
+ // Avoid Self
+ if (ent.equals(getEntity()))
+ {
+ continue;
+ }
+
+ // Creative or Spec
+ if (ent instanceof Player)
+ {
+ if (((Player) ent).getGameMode() == GameMode.CREATIVE || UtilPlayer.isSpectator(ent))
+ {
+ continue;
+ }
+ }
+
+ AxisAlignedBB axisalignedbb1 = ((CraftEntity) ent).getHandle().getBoundingBox().grow(1F, 1F, 1F);
+ MovingObjectPosition entityCollisionPosition = axisalignedbb1.a(vec3d, vec3d1);
+
+ if (entityCollisionPosition != null)
+ {
+ double d1 = vec3d.distanceSquared(entityCollisionPosition.pos);
+ if ((d1 < distanceToEntity) || (distanceToEntity == 0.0D))
+ {
+ victim = ent;
+ distanceToEntity = d1;
+ }
+ }
+ }
+ }
+
+ if (victim != null)
+ {
+ cur.getWorld().playEffect(victim.getEyeLocation().subtract(0, 0.5, 0), Effect.STEP_SOUND, cur.getBlockId());
+
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) victim, getEntity(), null,
+ DamageCause.CONTACT, 6 * getBoss().getDifficulty(), true, true, false, "Blocky Iron Wizard Aura",
+ "Blocky Iron Wizard Aura");
+ }
+
+ fallingIterator.remove();
+ cur.remove();
+
+ Vector vec = UtilAlg.getTrajectory(getEntity(), victim);
+ vec.setY(0).normalize();
+
+ double strength = 1;
+
+ if (!(victim instanceof Player) || !((Player) victim).isBlocking())
+ {
+ strength = 1.3;
+ }
+
+ UtilAction.velocity(victim, vec, strength, true, 0, 0.2, 1, true);
+ }
+ else if (finalObjectPosition != null)
+ {
+ Block block = cur.getWorld().getBlockAt(((int) finalObjectPosition.pos.a), ((int) finalObjectPosition.pos.b), ((int) finalObjectPosition.pos.c));
+
+ if (!UtilBlock.airFoliage(block) && !block.isLiquid())
+ {
+ nmsEntity.motX = ((float) (finalObjectPosition.pos.a - nmsEntity.locX));
+ nmsEntity.motY = ((float) (finalObjectPosition.pos.b - nmsEntity.locY));
+ nmsEntity.motZ = ((float) (finalObjectPosition.pos.c - nmsEntity.locZ));
+ float f2 = MathHelper.sqrt(
+ nmsEntity.motX * nmsEntity.motX + nmsEntity.motY * nmsEntity.motY + nmsEntity.motZ * nmsEntity.motZ);
+ nmsEntity.locX -= nmsEntity.motX / f2 * 0.0500000007450581D;
+ nmsEntity.locY -= nmsEntity.motY / f2 * 0.0500000007450581D;
+ nmsEntity.locZ -= nmsEntity.motZ / f2 * 0.0500000007450581D;
+
+ cur.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, cur.getBlockId());
+
+ fallingIterator.remove();
+ cur.remove();
+ }
+ }
+ else
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ cur.getLocation().add(0, 0.5, 0), 0.3F, 0.3F, 0.3F, 0, 2, UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplosiveBlock.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplosiveBlock.java
new file mode 100644
index 000000000..fd76b19e0
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemExplosiveBlock.java
@@ -0,0 +1,590 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+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;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Effect;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.util.Vector;
+
+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.itemstack.ItemBuilder;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import mineplex.minecraft.game.core.damage.CustomDamageEvent;
+import net.minecraft.server.v1_8_R3.AxisAlignedBB;
+import net.minecraft.server.v1_8_R3.DataWatcher;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+import net.minecraft.server.v1_8_R3.MathHelper;
+import net.minecraft.server.v1_8_R3.MovingObjectPosition;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayOutAttachEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity;
+import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving;
+import net.minecraft.server.v1_8_R3.Vec3D;
+
+public class GolemExplosiveBlock extends BossAbility
+{
+ private Map _blocksLocation = new HashMap<>();
+ private Location _center;
+ private int _explosionsLeft;
+ private FallingBlock _fallingBlock;
+ private Map _fallingBlocks = new HashMap<>();
+ private List- _items = new ArrayList<>();
+ private int _strength;
+ private Player _target;
+ private int _tick;
+
+ public GolemExplosiveBlock(GolemCreature creature, int strength)
+ {
+ super(creature);
+
+ _strength = strength;
+ _center = getLocation().add(0, 3, 0);
+ _target = getTarget();
+
+ if (_target != null)
+ {
+ UtilEnt.CreatureLook(getEntity(), _target);
+ }
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return _fallingBlock != null;
+ }
+
+ private int clamp(int value)
+ {
+ if (value < -127)
+ {
+ return -127;
+ }
+
+ if (value > 127)
+ {
+ return 127;
+ }
+
+ return value;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ HashMap locs = new HashMap();
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ double dist = player.getLocation().distance(_center);
+
+ if (dist < 30)
+ {
+ double score = (dist > 10 ? 30 - dist : 10);
+
+ for (Player p : UtilServer.getPlayers())
+ {
+ if (player.getLocation().distance(p.getLocation()) < 4)
+ {
+ score += 7;
+ }
+ }
+
+ if (player.hasLineOfSight(getEntity()))
+ {
+ score += 10;
+ }
+
+ locs.put(player, score);
+ }
+ }
+
+ Player lowest = null;
+
+ for (Entry entry : locs.entrySet())
+ {
+ if (lowest == null || locs.get(lowest) > locs.get(entry.getKey()))
+ {
+ lowest = entry.getKey();
+ }
+ }
+
+ return lowest;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _target == null || (_fallingBlock != null && !_fallingBlock.isValid() && _explosionsLeft == 0);
+ }
+
+ @EventHandler
+ public void onDamage(CustomDamageEvent event)
+ {
+ if (event.GetDamageeEntity().equals(getEntity()))
+ {
+ if (_tick >= 40 + (40 * _strength) && _tick <= 50 + (40 * _strength))
+ {
+ event.SetCancelled("Iron Wizard charging bomb");
+ }
+
+ event.SetKnockback(false);
+ }
+ }
+
+ public void onExplode(final Location loc)
+ {
+ for (int i = 0; i < _strength * 2; i++)
+ {
+ if (i == 0)
+ {
+ onSubExplode(loc);
+ }
+ else
+ {
+ _explosionsLeft++;
+
+ Bukkit.getScheduler().scheduleSyncDelayedTask(UtilServer.getPlugin(), () ->
+ {
+ onSubExplode(loc);
+ _explosionsLeft--;
+ }, 2 * i);
+ }
+ }
+ }
+
+ public void onSubExplode(Location loc)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ Location l = loc.clone().add(UtilMath.r(_strength * 4) - (_strength * 2), UtilMath.r(_strength * 2),
+ UtilMath.r(_strength * 4) - (_strength * 2));
+
+ UtilParticle.PlayParticle(ParticleType.LARGE_EXPLODE, l, _strength * 3, 1, _strength * 3, 0, _strength * 4,
+ ViewDist.LONG, UtilServer.getPlayers());
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onUpdate(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ if (_fallingBlock == null)
+ {
+ return;
+ }
+
+ if (_fallingBlock.isDead()
+ || !_fallingBlock.isValid()
+ || _fallingBlock.getTicksLived() > 400
+ || !_fallingBlock.getWorld().isChunkLoaded(_fallingBlock.getLocation().getBlockX() >> 4,
+ _fallingBlock.getLocation().getBlockZ() >> 4))
+ {
+ Block block = _fallingBlock.getLocation().getBlock();
+ block.setTypeIdAndData(0, (byte) 0, true);
+ _fallingBlock.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, _fallingBlock.getBlockId());
+
+ // Expire
+ if (_fallingBlock.getTicksLived() > 400
+ || !_fallingBlock.getWorld().isChunkLoaded(_fallingBlock.getLocation().getBlockX() >> 4,
+ _fallingBlock.getLocation().getBlockZ() >> 4))
+ {
+ _fallingBlock.remove();
+ return;
+ }
+
+ _fallingBlock.remove();
+ return;
+ }
+
+ double distanceToEntity = 0.0D;
+ LivingEntity victim = null;
+
+ net.minecraft.server.v1_8_R3.Entity nmsEntity = ((CraftEntity) _fallingBlock).getHandle();
+ Vec3D vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ Vec3D vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ MovingObjectPosition finalObjectPosition = nmsEntity.world.rayTrace(vec3d, vec3d1, false, true, false);
+ vec3d = new Vec3D(nmsEntity.locX, nmsEntity.locY, nmsEntity.locZ);
+ vec3d1 = new Vec3D(nmsEntity.locX + nmsEntity.motX, nmsEntity.locY + nmsEntity.motY, nmsEntity.locZ + nmsEntity.motZ);
+
+ if (finalObjectPosition != null)
+ {
+ vec3d1 = new Vec3D(finalObjectPosition.pos.a, finalObjectPosition.pos.b, finalObjectPosition.pos.c);
+ }
+
+ for (Object entity : ((CraftWorld) _fallingBlock.getWorld()).getHandle().getEntities(
+ ((CraftEntity) _fallingBlock).getHandle(),
+ ((CraftEntity) _fallingBlock).getHandle().getBoundingBox().a(((CraftEntity) _fallingBlock).getHandle().motX,
+ ((CraftEntity) _fallingBlock).getHandle().motY, ((CraftEntity) _fallingBlock).getHandle().motZ).grow(2,
+ 2, 2)))
+ {
+ Entity bukkitEntity = ((net.minecraft.server.v1_8_R3.Entity) entity).getBukkitEntity();
+
+ if (bukkitEntity instanceof LivingEntity)
+ {
+ LivingEntity ent = (LivingEntity) bukkitEntity;
+
+ // Avoid Self
+ if (ent.equals(getEntity()))
+ {
+ continue;
+ }
+
+ // Creative or Spec
+ if (ent instanceof Player)
+ {
+ if (((Player) ent).getGameMode() == GameMode.CREATIVE || UtilPlayer.isSpectator(ent))
+ {
+ continue;
+ }
+ }
+
+ // float f1 = (float)(nmsEntity.boundingBox.a() * 0.6f);
+ AxisAlignedBB axisalignedbb1 = ((CraftEntity) ent).getHandle().getBoundingBox().grow(1F, 1F, 1F);
+ MovingObjectPosition entityCollisionPosition = axisalignedbb1.a(vec3d, vec3d1);
+
+ if (entityCollisionPosition != null)
+ {
+ double d1 = vec3d.distanceSquared(entityCollisionPosition.pos);
+ if ((d1 < distanceToEntity) || (distanceToEntity == 0.0D))
+ {
+ victim = ent;
+ distanceToEntity = d1;
+ }
+ }
+ }
+ }
+
+ if (victim != null)
+ {
+ onExplode(victim.getEyeLocation());
+
+ _fallingBlock.remove();
+ }
+ else if (finalObjectPosition != null)
+ {
+ Block block = _fallingBlock.getWorld()
+ .getBlockAt(((int) finalObjectPosition.pos.a), ((int) finalObjectPosition.pos.b), ((int) finalObjectPosition.pos.c));
+
+ if (!UtilBlock.airFoliage(block) && !block.isLiquid())
+ {
+ nmsEntity.motX = ((float) (finalObjectPosition.pos.a - nmsEntity.locX));
+ nmsEntity.motY = ((float) (finalObjectPosition.pos.b - nmsEntity.locY));
+ nmsEntity.motZ = ((float) (finalObjectPosition.pos.c - nmsEntity.locZ));
+ float f2 = MathHelper.sqrt(nmsEntity.motX * nmsEntity.motX + nmsEntity.motY * nmsEntity.motY + nmsEntity.motZ
+ * nmsEntity.motZ);
+ nmsEntity.locX -= nmsEntity.motX / f2 * 0.0500000007450581D;
+ nmsEntity.locY -= nmsEntity.motY / f2 * 0.0500000007450581D;
+ nmsEntity.locZ -= nmsEntity.motZ / f2 * 0.0500000007450581D;
+
+ onExplode(block.getLocation().add(0.5, 0.5, 0.5));
+
+ _fallingBlock.remove();
+ }
+ }
+ else
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ _fallingBlock.getLocation().add(0, 0.5, 0), 0.3F, 0.3F, 0.3F, 0, 2, UtilParticle.ViewDist.NORMAL,
+ UtilServer.getPlayers());
+ }
+ }
+
+ @Override
+ public void setFinished()
+ {
+ int[] ids = new int[_fallingBlocks.size() * 2];
+
+ int index = 0;
+
+ for (Entry entry : _fallingBlocks.entrySet())
+ {
+ ids[index] = entry.getKey();
+ ids[index + 1] = entry.getValue();
+ index += 2;
+ }
+
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ids);
+
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+
+ for (Item item : _items)
+ {
+ item.remove();
+ }
+
+ if (_fallingBlock != null)
+ {
+ _fallingBlock.remove();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ IronGolem entity = getEntity();
+
+ Iterator
- itel = _items.iterator();
+
+ while (itel.hasNext())
+ {
+ Item item = itel.next();
+
+ Vector vec = item.getVelocity();
+ Location loc = item.getLocation();
+
+ if (item.getTicksLived() > 100 || vec.getY() <= 0 || loc.distance(_center) > loc.add(vec).distance(_center)
+ || UtilEnt.isGrounded(item))
+ {
+ itel.remove();
+ }
+ }
+
+ // This spawns a floating block
+ if (_tick >= 20 && _tick % 60 == 0 && _fallingBlocks.size() < _strength)
+ {
+ int id = UtilEnt.getNewEntityId();
+ int id2 = UtilEnt.getNewEntityId();
+
+ _fallingBlocks.put(id, id2);
+ _blocksLocation.put(id, _center.toVector());
+
+ Packet>[] packets = new Packet[3];
+
+ PacketPlayOutSpawnEntityLiving packet1 = new PacketPlayOutSpawnEntityLiving();
+
+ DataWatcher watcher = new DataWatcher(null);
+ watcher.a(0, (byte) 32, net.minecraft.server.v1_8_R3.Entity.META_ENTITYDATA, (byte) 0);
+ watcher.a(1, 0, net.minecraft.server.v1_8_R3.Entity.META_AIR, 0);
+
+ packet1.a = id;
+ packet1.b = EntityType.SILVERFISH.getTypeId();
+ packet1.c = (int) Math.floor(_center.getX() * 32);
+ packet1.d = (int) Math.floor((_center.getY() - 0.125) * 32);
+ packet1.e = (int) Math.floor(_center.getZ() * 32);
+ packet1.l = watcher;
+
+ packets[0] = packet1;
+
+ PacketPlayOutSpawnEntity packet2 = new PacketPlayOutSpawnEntity(((CraftEntity) entity).getHandle(), 70,
+ Material.DIRT.getId());
+
+ packet2.a = id2;
+
+ packet2.b = (int) Math.floor(_center.getX() * 32);
+ packet2.c = (int) Math.floor(_center.getY() * 32);
+ packet2.d = (int) Math.floor(_center.getZ() * 32);
+
+ packets[1] = packet2;
+
+ PacketPlayOutAttachEntity packet3 = new PacketPlayOutAttachEntity();
+
+ packet3.b = id2;
+ packet3.c = id;
+
+ packets[2] = packet3;
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ if (player.getLocation().distance(_center) < 80)
+ {
+ UtilPlayer.sendPacket(player, packets);
+ }
+ }
+ }
+
+ // This spawns a item that flies above the golem's head and disappears
+ if (UtilMath.r(6) == 0 && _tick < 40 + (_strength * 40))
+ {
+ double angle = ((2 * Math.PI) / 30) * UtilMath.r(30);
+ double x = 5 * Math.cos(angle);
+ double z = 5 * Math.sin(angle);
+ Location loc = _center.clone().add(x, -3, z);
+
+ Material mat = null;
+
+ switch (UtilMath.r(3))
+ {
+ case 0:
+ mat = Material.DIRT;
+ break;
+ case 1:
+ mat = Material.STONE;
+ break;
+ case 2:
+ mat = Material.COBBLESTONE;
+ break;
+ default:
+ break;
+ }
+
+ Item item = loc.getWorld().dropItem(loc, new ItemBuilder(mat).setTitle(System.currentTimeMillis() + "").build());
+
+ item.setPickupDelay(999999);
+
+ Vector vec = UtilAlg.getTrajectory(_center, item.getLocation());
+
+ vec.normalize().multiply(5);
+
+ item.setVelocity(vec);
+
+ // TODO Fix velocity
+
+ _items.add(item);
+ }
+
+ // 10 being when items no longer fly in, 0 being when its shot.
+ int ticksTillFired = (60 + (40 * _strength)) - _tick;
+
+ if (ticksTillFired > 20)
+ {
+ int strength = (int) Math.floor(_tick / 20D);
+
+ int nine = 8 - strength;
+
+ if (_tick % nine == 0)
+ {
+ _center.getWorld().playSound(_center, Sound.DIG_GRASS, strength + 1, 1F);
+ }
+ }
+ else if (ticksTillFired < 0)
+ {
+ if (_tick % 3 == 0)
+ {
+ _center.getWorld().playSound(_fallingBlock.getLocation(), Sound.WOOD_CLICK, _strength + 1, 0.4F);
+ }
+ }
+
+ // The location the falling blocks need to stick by
+ Vector blockCenter = _center.toVector();
+
+ if (ticksTillFired >= 0 && ticksTillFired <= 20)
+ {
+ Vector vec = entity.getLocation().add(entity.getLocation().getDirection().setY(0).normalize().multiply(1.2))
+ .add(0, 1, 0).toVector();
+
+ blockCenter = UtilAlg.getTrajectory(_center.toVector(), blockCenter);
+ vec.multiply(ticksTillFired / 10D);
+
+ _center.getWorld().playSound(_center, Sound.DIG_SNOW, _strength + 1, 0);
+ }
+ else if (_fallingBlock != null)
+ {
+ blockCenter = _fallingBlock.getLocation().add(0, 0.5, 0).toVector();
+ }
+
+ // Move the fake floating blocks
+ for (Entry entry : _fallingBlocks.entrySet())
+ {
+ int id = entry.getKey();
+ Vector vec = _blocksLocation.get(id);
+
+ int x = clamp((int) ((blockCenter.getX() - vec.getX()) * 32) + (UtilMath.r(8) - 4));
+ int y = clamp((int) ((blockCenter.getY() - vec.getY()) * 32) + (UtilMath.r(8) - 4));
+ int z = clamp((int) ((blockCenter.getZ() - vec.getZ()) * 32) + (UtilMath.r(8) - 4));
+
+ vec.add(new Vector(x, y, z));
+
+ PacketPlayOutEntity.PacketPlayOutRelEntityMove packet = new PacketPlayOutEntity.PacketPlayOutRelEntityMove();
+
+ packet.a = id;
+
+ packet.b = (byte) x;
+ packet.c = (byte) y;
+ packet.d = (byte) z;
+
+ for (Player player : UtilServer.getPlayers())
+ {
+ if (player.getLocation().distance(_center) < 70)
+ {
+ UtilPlayer.sendPacket(player, packet);
+
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.STONE, 0),
+ vec.toLocation(_center.getWorld()), 0.7F, 0.7F, 0.7F, 0, 11, ViewDist.NORMAL, player);
+ }
+ }
+ }
+
+ if (ticksTillFired == 0)
+ {
+ int id = _fallingBlocks.keySet().iterator().next();
+
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(new int[]
+ {
+ id, _fallingBlocks.get(id)
+ });
+
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ UtilPlayer.sendPacket(player, packet);
+ }
+
+ _fallingBlocks.remove(id);
+
+ _fallingBlock = _center.getWorld().spawnFallingBlock(_blocksLocation.get(id).toLocation(_center.getWorld()),
+ Material.STONE, (byte) 0);
+
+ Vector vec1 = _fallingBlock.getLocation().toVector();
+ Vector vec2 = _target.getLocation().toVector();
+
+ Vector vec = UtilAlg.calculateVelocity(vec1, vec2, (int) (vec1.distanceSquared(vec2) / 4));
+
+ _fallingBlock.setVelocity(vec);
+
+ EntityIronGolem golem = ((CraftIronGolem) entity).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+ }
+
+ _tick++;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemIronHook.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemIronHook.java
new file mode 100644
index 000000000..18c94e4cd
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemIronHook.java
@@ -0,0 +1,163 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Sound;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
+
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilAlg;
+import mineplex.core.common.util.UtilParticle.ParticleType;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilServer;
+import mineplex.core.itemstack.ItemStackFactory;
+import mineplex.core.updater.UpdateType;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+
+public class GolemIronHook extends BossAbility
+{
+ private static final Integer MAX_TARGETS = 3;
+ private boolean _shot, _complete;
+
+ private List
- _hooks = new ArrayList<>();
+
+ public GolemIronHook(GolemCreature creature)
+ {
+ super(creature);
+ _shot = false;
+ _complete = false;
+ }
+
+ private int getPosition(Player toAdd, List ordered, Map distances)
+ {
+ int position = ordered.size();
+ int index = 0;
+ for (Player player : ordered)
+ {
+ if (distances.get(player) < distances.get(toAdd))
+ {
+ position = index;
+ }
+ index++;
+ }
+
+ return position;
+ }
+
+ private void shoot()
+ {
+ IronGolem wizard = getBoss().getEntity();
+ List selections = new LinkedList<>();
+ List targeted = new ArrayList<>();
+
+ Map near = UtilPlayer.getInRadius(wizard.getLocation(), 40D);
+
+ for (Player nearby : near.keySet())
+ {
+ if (nearby.getGameMode() == GameMode.CREATIVE || nearby.getGameMode() == GameMode.SPECTATOR)
+ {
+ continue;
+ }
+
+ if (selections.isEmpty())
+ {
+ selections.add(nearby);
+ }
+ else
+ {
+ selections.add(getPosition(nearby, selections, near), nearby);
+ }
+ }
+
+ for (int i = 0; i < MAX_TARGETS; i++)
+ {
+ if (i < selections.size())
+ {
+ targeted.add(selections.get(i));
+ }
+ }
+
+ if (targeted.isEmpty())
+ {
+ _complete = true;
+ setFinished();
+ return;
+ }
+
+ for (Player target : targeted)
+ {
+ Item item = wizard.getWorld().dropItem(wizard.getEyeLocation().add(UtilAlg.getTrajectory(wizard, target)), ItemStackFactory.Instance.CreateStack(131));
+ UtilAction.velocity(item, UtilAlg.getTrajectory(wizard, target).normalize(),
+ 2, false, 0, 0.2, 20, false);
+
+ getBoss().getEvent().getProjectileManager().AddThrow(item, getBoss().getEntity(), new IronHook(getBoss().getEvent()), -1, true, true, true, true,
+ Sound.FIRE_IGNITE, 1.4f, 0.8f, ParticleType.CRIT, UpdateType.TICK, 1f);
+
+ item.getWorld().playSound(item.getLocation(), Sound.IRONGOLEM_THROW, 2f, 0.8f);
+ _hooks.add(item);
+ }
+ }
+
+ @Override
+ public int getCooldown()
+ {
+ return 10;
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _complete;
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (Item hook : _hooks)
+ {
+ if (!hook.isDead() && hook.isValid())
+ {
+ getBoss().getEvent().getProjectileManager().deleteThrown(hook);
+ hook.remove();
+ }
+ }
+
+ _hooks.clear();
+ }
+
+ @Override
+ public void tick()
+ {
+ if (_shot)
+ {
+ return;
+ }
+ shoot();
+ _shot = true;
+ Bukkit.getScheduler().runTaskLater(UtilServer.getPlugin(), () ->
+ {
+ _complete = true;
+ setFinished();
+ }, 2 * 20);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemMeleeAttack.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemMeleeAttack.java
new file mode 100644
index 000000000..a045429dc
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemMeleeAttack.java
@@ -0,0 +1,90 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import org.bukkit.Sound;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+
+public class GolemMeleeAttack extends BossAbility
+{
+ private boolean _attacked;
+
+ public GolemMeleeAttack(GolemCreature creature)
+ {
+ super(creature);
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return true;
+ }
+
+ @Override
+ public int getCooldown()
+ {
+ return 20;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ return getTarget(4);
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _attacked;
+ }
+
+ @Override
+ public void setFinished() {}
+
+ @Override
+ public void tick()
+ {
+ _attacked = true;
+
+ for (Player target : UtilPlayer.getNearby(getLocation(), 4, true))
+ {
+ if (target.getVelocity().length() > 0.5)
+ {
+ continue;
+ }
+
+ UtilEnt.CreatureLook(getEntity(), target);
+
+ getBoss().getEvent().getDamageManager().NewDamageEvent(target, getEntity(), null, DamageCause.ENTITY_ATTACK,
+ 10 * getBoss().getDifficulty(), false, true, false, "Iron Wizard Melee Attack", "Iron Wizard Melee Attack");
+
+ Vector vec = getLocation().getDirection();
+ vec.setY(0).normalize().setY(0.5).multiply(2.4);
+
+ UtilAction.velocity(target, vec);
+
+ getBoss().getEvent().getCondition().Factory().Falling("Iron Wizard Throw", target, getEntity(), 3, false, false);
+
+ target.getWorld().playSound(target.getLocation(), Sound.IRONGOLEM_THROW, 3, 0.9F);
+
+ EntityIronGolem golem = ((CraftIronGolem) getEntity()).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+ }
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return _attacked;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRumble.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRumble.java
new file mode 100644
index 000000000..d9cb7cc70
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRumble.java
@@ -0,0 +1,238 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Effect;
+import org.bukkit.Location;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.Damageable;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.util.Vector;
+
+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.UtilPlayer;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+
+/**
+ * Rumble is where the golem picks a target then starts playing a animation for a second where its obviously preparing to use it.
+ * Copy this from Wizards
+ */
+public class GolemRumble extends BossAbility
+{
+ private Location _loc;
+ private int _ticks;
+ private int _travelled;
+ private Vector _vec;
+ private int _width = 1;
+ private Location _target;
+
+ public GolemRumble(GolemCreature creature)
+ {
+ super(creature);
+
+ Player target = getTarget();
+
+ if (target != null)
+ {
+ _target = target.getLocation();
+
+ UtilEnt.CreatureLook(getEntity(), _target);
+ }
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return _ticks >= 20;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _travelled > 35;
+ }
+
+ @Override
+ public void setFinished() {}
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public void tick()
+ {
+ if (_ticks++ < 14)
+ {
+ IronGolem entity = getEntity();
+ EntityIronGolem golem = ((CraftIronGolem) entity).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+
+ if (_ticks % 2 == 0)
+ {
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 3, 2F);
+ }
+ }
+ else if (_ticks % 2 == 0)
+ {
+ int oldWidth = _width;
+
+ if ((_width <= 3 || _ticks % 4 == 0) && _width <= 6)
+ {
+ _width++;
+ }
+
+ Location newLoc;
+ boolean validBlock = false;
+ List current = new ArrayList<>();
+
+ if (_vec == null)
+ {
+ _vec = _target.subtract(getLocation()).toVector().setY(0).normalize();
+ _loc = getLocation().subtract(0, 1, 0).getBlock().getLocation().add(0, 0.99, 0);
+ newLoc = _loc;
+ current.add(_loc.getBlock());
+
+ validBlock = true;
+ }
+ else
+ { // Move rumble
+ newLoc = _loc.clone().add(_vec);
+
+ // Check if the rumble needs to go up or drop a block or two
+ for (int y : new int[] {0, 1, -1})
+ {
+ for (int a = 1; a <= 2; a++)
+ {
+ Block b = newLoc.clone().add(_vec.clone().multiply(a)).getBlock().getRelative(0, y, 0);
+
+ if (UtilBlock.solid(b) && !UtilBlock.solid(b.getRelative(0, 1, 0)))
+ {
+ validBlock = true;
+ newLoc.add(0, y, 0);
+
+ break;
+ }
+ }
+
+ if (validBlock)
+ {
+ break;
+ }
+ }
+
+ for (int width = -_width; width <= _width; width++)
+ {
+ if (Math.abs(width) <= oldWidth)
+ {
+ Block b = _loc.clone().add(UtilAlg.getRight(_vec).multiply(width)).getBlock();
+
+ if (!current.contains(b))
+ {
+ current.add(b);
+ }
+ }
+
+ if (validBlock)
+ {
+ Block b = newLoc.clone().add(UtilAlg.getRight(_vec).multiply(width)).getBlock();
+
+ if (!current.contains(b))
+ {
+ current.add(b);
+
+ b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getTypeId());
+ }
+ }
+ }
+ }
+
+ UtilEnt.CreatureLook(getEntity(), _loc);
+
+ for (Entity entity : getEntity().getWorld().getEntities())
+ {
+ if (entity instanceof Damageable && !UtilPlayer.isSpectator(entity) && entity != getEntity())
+ {
+ Block b = entity.getLocation().getBlock();
+ boolean canDamage = false;
+
+ for (int y = -1; y <= 0; y++)
+ {
+ if (current.contains(b.getRelative(0, y, 0)))
+ {
+ canDamage = true;
+ break;
+ }
+ }
+
+ if (!canDamage)
+ {
+ continue;
+ }
+
+ if (canDamage(entity))
+ {
+ getBoss().getEvent().getDamageManager().NewDamageEvent((LivingEntity) entity, getEntity(), null,
+ DamageCause.CONTACT, 8 * getBoss().getDifficulty(), false, true, false, "Iron Wizard Rumble",
+ "Iron Wizard Rumble");
+ }
+
+ UtilAction.velocity(entity, _vec.clone(), 1.5, true, 0, 0.2, 1, true);
+
+ if (entity instanceof Player)
+ {
+ getBoss().getEvent().getCondition().Factory().Slow("Rumble", (LivingEntity) entity, getEntity(), 3, 1,
+ false, false, false, false);
+ }
+ }
+ }
+
+ if (_travelled++ > 35 || !validBlock)
+ {
+ _travelled = 100;
+ }
+
+ _loc = newLoc;
+ }
+ }
+
+ public Player getTarget()
+ {
+ Player target = null;
+ double dist = 0;
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), 30, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(getLocation());
+
+ if (d > 2 && (target == null || dist > d))
+ {
+ target = player;
+ dist = d;
+ }
+ }
+
+ return target;
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return _ticks < 14;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRupture.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRupture.java
new file mode 100644
index 000000000..2ecf4c46b
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemRupture.java
@@ -0,0 +1,367 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Effect;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftIronGolem;
+import org.bukkit.entity.IronGolem;
+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.inventory.InventoryPickupItemEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.Pair;
+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.UtilTime;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+import net.minecraft.server.v1_8_R3.EntityIronGolem;
+
+public class GolemRupture extends BossAbility
+{
+ private List> _ruptures = new ArrayList<>();
+ private Map _ruptureTime = new HashMap<>();
+ private List _targetted = new ArrayList<>();
+ private int _rupturesLeft;
+ private int _tick;
+ private List
- _items = new ArrayList<>();
+ private int _ticksFinished;
+
+ public GolemRupture(GolemCreature creature)
+ {
+ super(creature);
+
+ if (creature.getHealthPercent() > 0.75)
+ {
+ _rupturesLeft = 2;
+ }
+ else if (creature.getHealthPercent() > 0.5)
+ {
+ _rupturesLeft = 5;
+ }
+ else
+ {
+ _rupturesLeft = 10;
+ }
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return false;
+ }
+
+ @EventHandler
+ public void HopperPickup(InventoryPickupItemEvent event)
+ {
+ if (_items.contains(event.getItem()))
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void ItemDestroy(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ if (_items.isEmpty())
+ {
+ return;
+ }
+
+ Iterator
- itemIterator = _items.iterator();
+
+ while (itemIterator.hasNext())
+ {
+ Item item = itemIterator.next();
+
+ if (item.isDead() || !item.isValid())
+ {
+ item.remove();
+ itemIterator.remove();
+ }
+ else if (UtilEnt.isGrounded(item) || item.getTicksLived() > 60)
+ {
+ item.getWorld().playEffect(item.getLocation(), Effect.STEP_SOUND, item.getItemStack().getTypeId());
+ item.remove();
+ itemIterator.remove();
+ }
+ }
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _rupturesLeft <= 0 && _ruptures.isEmpty() && --_ticksFinished <= 0;
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (Item item : _items)
+ {
+ item.remove();
+ }
+ }
+
+ @Override
+ public void tick()
+ {
+ Iterator> itel = _ruptures.iterator();
+
+ while (itel.hasNext())
+ {
+ Pair pair = itel.next();
+
+ if (pair.getLeft().distance(pair.getRight()) > 0)
+ {
+ Vector vec = pair.getRight().toVector().subtract(pair.getLeft().toVector());
+
+ if (vec.length() > 1)
+ {
+ vec = vec.normalize();
+ }
+
+ pair.getLeft().add(vec);
+ }
+
+ if (pair.getLeft().distance(pair.getRight()) < 0.1)
+ {
+ if (!_ruptureTime.containsKey(pair.getLeft()))
+ {
+ _ruptureTime.put(pair.getLeft(), System.currentTimeMillis());
+ }
+ else if (UtilTime.elapsed(_ruptureTime.get(pair.getLeft()), 150))
+ {
+ itel.remove();
+
+ explodeRupture(pair.getLeft());
+ }
+ }
+ }
+
+ if (_tick % 10 == 0 && _rupturesLeft > 0)
+ {
+ _rupturesLeft--;
+
+ Location loc = getLocation().add(UtilMath.random.nextFloat() - 0.5, 0, UtilMath.random.nextFloat() - 0.5);
+
+ loc.setY(loc.getBlockY());
+
+ for (int y = 0; y > -3; y--)
+ {
+ if (!UtilBlock.airFoliage(loc.getBlock().getRelative(0, y, 0)))
+ {
+ loc.setY(loc.getY() + y);
+ break;
+ }
+ }
+
+ Player player = getTarget();
+
+ if (player != null)
+ {
+ _targetted.add(player.getName());
+
+ Location target = player.getLocation();
+ target.setY(loc.getY());
+
+ _ruptures.add(Pair.create(loc, target));
+
+ UtilEnt.CreatureLook(getEntity(), player.getLocation());
+
+ EntityIronGolem golem = ((CraftIronGolem) getEntity()).getHandle();
+
+ golem.world.broadcastEntityEffect(golem, (byte) 4);
+ }
+ else
+ {
+ _rupturesLeft = 0;
+ }
+ }
+
+ for (Pair pair : _ruptures)
+ {
+ pair.getLeft().getWorld().playSound(pair.getLeft(), Sound.DIG_GRAVEL, 2.5F, 0.9F);
+
+ {
+ UtilParticle.PlayParticle(ParticleType.BLOCK_DUST.getParticle(Material.DIRT, 0),
+ pair.getLeft().clone().add(0, 1.1, 0), 1F, 0, 1F, 0, 70, ViewDist.NORMAL, UtilServer.getPlayers());
+ }
+ }
+
+ _tick++;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ Player target = null;
+ double dist = 0;
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), 30, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ if (_targetted.contains(player.getName()))
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(getLocation());
+
+ if (d < 7)
+ {
+ continue;
+ }
+
+ boolean valid = true;
+
+ for (Pair loc : _ruptures)
+ {
+ if (loc.getRight().distance(player.getLocation()) < 1.5)
+ {
+ valid = false;
+ break;
+ }
+ }
+
+ if (!valid)
+ {
+ continue;
+ }
+
+ if (target == null || dist > d)
+ {
+ target = player;
+ dist = d;
+ }
+ }
+
+ return target;
+ }
+
+ @SuppressWarnings("deprecation")
+ private void explodeRupture(Location loc)
+ {
+ loc.add(0, 1.1, 0);
+ loc.setX(loc.getBlockX() + 0.5);
+ loc.setZ(loc.getBlockZ() + 0.5);
+
+ // Fling
+ HashMap targets = UtilEnt.getInRadius(loc, 3.5);
+ for (LivingEntity cur : targets.keySet())
+ {
+ // Velocity
+ UtilAction.velocity(cur,
+ UtilAlg.getTrajectory2d(loc.toVector().add(new Vector(0.5, 0, 0.5)), cur.getLocation().toVector()),
+ 0.8 + 0.8 * targets.get(cur), true, 0, 0.4 + 1.0 * targets.get(cur), 1.4, true);
+
+ // Condition
+ getBoss().getEvent().getCondition().Factory().Falling("Rupture", cur, getEntity(), 10, false, true);
+
+ // Damage Event
+ getBoss().getEvent().getDamageManager().NewDamageEvent(cur, getEntity(), null, DamageCause.CUSTOM,
+ 8 * getBoss().getDifficulty(), false, true, false, "Iron Wizard", "Rupture");
+ }
+
+ List blocks = new ArrayList<>();
+
+ for (int x = -3; x <= 3; x++)
+ {
+ for (int z = -3; z <= 3; z++)
+ {
+ for (int y = 0; y <= 1; y++)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ if (Math.sqrt(x * x + z * z + y * y) <= 3)
+ {
+ blocks.add(loc.clone().add(x, y, z).getBlock());
+ }
+ }
+ }
+ }
+ }
+
+ Collections.shuffle(blocks);
+
+ // Blocks
+ int done = 0;
+ Iterator itel = blocks.iterator();
+
+ while (done < 30 && itel.hasNext())
+ {
+ Block block = itel.next();
+
+ Vector vec = new Vector(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
+
+ if (!UtilBlock.airFoliage(block))
+ {
+ continue;
+ }
+
+ // Add Directional
+ vec.add(UtilAlg.getTrajectory(loc.getBlock().getLocation(), block.getLocation().add(0.5, 0, 0.5)));
+
+ // Add Up
+ vec.add(new Vector(0, 1.6, 0));
+
+ vec.normalize();
+
+ // Scale
+ vec.multiply(0.1 + 0.3 * Math.random() + 0.6);
+
+ // Block!
+ Item item = loc.getWorld().dropItem(block.getLocation().add(0.5, 0, 0.5), new ItemStack(Material.DIRT, 0));
+ item.setVelocity(vec);
+ item.setPickupDelay(50000);
+ _items.add(item);
+
+ // Effect
+ loc.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, Material.STONE.getId());
+
+ done++;
+ }
+
+ _ticksFinished = 20;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSlam.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSlam.java
new file mode 100644
index 000000000..c4a5a01ab
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSlam.java
@@ -0,0 +1,271 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Effect;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.IronGolem;
+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.inventory.InventoryPickupItemEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+
+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.UtilPlayer;
+import mineplex.core.updater.UpdateType;
+import mineplex.core.updater.event.UpdateEvent;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+
+public class GolemSlam extends BossAbility
+{
+ private List
- _items = new ArrayList<>();
+ private int _ticksFinished;
+ private int _stage;
+ private Vector _target;
+ private int _ticksJumped;
+
+ public GolemSlam(GolemCreature creature)
+ {
+ super(creature);
+
+ Player target = getTarget();
+
+ if (target != null)
+ {
+ _target = UtilAlg.calculateVelocity(getLocation().toVector(),
+ target.getLocation().toVector().setY(getLocation().getY()), 2, getEntity());
+ }
+ }
+
+ @Override
+ public boolean canMove()
+ {
+ return !UtilEnt.isGrounded(getEntity()) && _stage == 1;
+ }
+
+ @Override
+ public boolean hasFinished()
+ {
+ return _stage == 2 && --_ticksFinished <= 0;
+ }
+
+ @Override
+ public void setFinished()
+ {
+ for (Item item : _items)
+ {
+ item.remove();
+ }
+ }
+
+ @Override
+ public void tick()
+ {
+ Entity entity = getEntity();
+
+ if (_stage == 0)
+ {
+ UtilEnt.CreatureLook(getEntity(), getLocation().add(_target));
+
+ entity.getWorld().playSound(entity.getLocation(), Sound.IRONGOLEM_THROW, 4, 0);
+
+ entity.setVelocity(_target);
+ _stage++;
+ }
+ else if (_stage == 1)
+ {
+ _ticksJumped++;
+
+ if (_ticksJumped > 4 && getLocation().subtract(0, 0.2, 0).getBlock().getType() != Material.AIR)
+ {
+ explodeRupture(getLocation());
+
+ _stage = 2;
+ }
+ }
+ }
+
+ @EventHandler
+ public void HopperPickup(InventoryPickupItemEvent event)
+ {
+ if (_items.contains(event.getItem()))
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void ItemDestroy(UpdateEvent event)
+ {
+ if (event.getType() != UpdateType.TICK)
+ {
+ return;
+ }
+
+ if (_items.isEmpty())
+ {
+ return;
+ }
+
+ Iterator
- itemIterator = _items.iterator();
+
+ while (itemIterator.hasNext())
+ {
+ Item item = itemIterator.next();
+
+ if (item.isDead() || !item.isValid())
+ {
+ item.remove();
+ itemIterator.remove();
+ }
+ else if (UtilEnt.isGrounded(item) || item.getTicksLived() > 60)
+ {
+ item.getWorld().playEffect(item.getLocation(), Effect.STEP_SOUND, item.getItemStack().getTypeId());
+ item.remove();
+ itemIterator.remove();
+ }
+ }
+ }
+
+ @Override
+ public boolean inProgress()
+ {
+ return true;
+ }
+
+ @Override
+ public Player getTarget()
+ {
+ Player target = null;
+ double dist = 0;
+
+ for (Player player : UtilPlayer.getNearby(getLocation(), 30, true))
+ {
+ if (!player.hasLineOfSight(getEntity()))
+ {
+ continue;
+ }
+
+ double d = player.getLocation().distance(getLocation());
+
+ if (d < 10)
+ {
+ continue;
+ }
+
+ if (target == null || dist > d)
+ {
+ target = player;
+ dist = d;
+ }
+ }
+
+ return target;
+ }
+
+ @SuppressWarnings("deprecation")
+ private void explodeRupture(Location loc)
+ {
+ loc.add(0, 1.1, 0);
+ loc.setX(loc.getBlockX() + 0.5);
+ loc.setZ(loc.getBlockZ() + 0.5);
+
+ // Fling
+ Map targets = UtilEnt.getInRadius(loc, 3.5);
+ for (LivingEntity cur : targets.keySet())
+ {
+ if (cur.equals(getEntity()))
+ {
+ continue;
+ }
+
+ // Velocity
+ UtilAction.velocity(cur,
+ UtilAlg.getTrajectory2d(loc.toVector().add(new Vector(0.5, 0, 0.5)), cur.getLocation().toVector()),
+ 0.8 + 0.8 * targets.get(cur), true, 0, 0.4 + 1.0 * targets.get(cur), 1.4, true);
+
+ // Condition
+ getBoss().getEvent().getCondition().Factory().Falling("Rupture", cur, getEntity(), 10, false, true);
+
+ // Damage Event
+ getBoss().getEvent().getDamageManager().NewDamageEvent(cur, getEntity(), null, DamageCause.CUSTOM,
+ 8 * getBoss().getDifficulty(), false, true, false, "Iron Wizard", "Rupture");
+ }
+
+ List blocks = new ArrayList();
+
+ for (int x = -3; x <= 3; x++)
+ {
+ for (int z = -3; z <= 3; z++)
+ {
+ for (int y = 0; y <= 1; y++)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ if (Math.sqrt(x * x + z * z + y * y) <= 3)
+ {
+ blocks.add(loc.clone().add(x, y, z).getBlock());
+ }
+ }
+ }
+ }
+ }
+
+ Collections.shuffle(blocks);
+
+ // Blocks
+ int done = 0;
+ Iterator itel = blocks.iterator();
+
+ while (done < 30 && itel.hasNext())
+ {
+ Block block = itel.next();
+
+ Vector vec = new Vector(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize();
+
+ if (!UtilBlock.airFoliage(block))
+ continue;
+
+ // Add Directional
+ vec.add(UtilAlg.getTrajectory(loc.getBlock().getLocation(), block.getLocation().add(0.5, 0, 0.5)));
+
+ // Add Up
+ vec.add(new Vector(0, 1.6, 0));
+
+ vec.normalize();
+
+ // Scale
+ vec.multiply(0.1 + 0.3 * Math.random() + 0.6);
+
+ // Block!
+ Item item = loc.getWorld().dropItem(block.getLocation().add(0.5, 0, 0.5), new ItemStack(Material.DIRT, 0));
+ item.setVelocity(vec);
+ item.setPickupDelay(50000);
+ _items.add(item);
+
+ // Effect
+ loc.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, Material.DIRT.getId());
+
+ done++;
+ }
+
+ _ticksFinished = 20;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSpike.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSpike.java
new file mode 100644
index 000000000..4f5dad106
--- /dev/null
+++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/worldevent/boss/ironwizard/abilities/GolemSpike.java
@@ -0,0 +1,104 @@
+package mineplex.game.clans.clans.worldevent.boss.ironwizard.abilities;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.bukkit.Sound;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.util.Vector;
+
+import mineplex.core.common.util.UtilAction;
+import mineplex.core.common.util.UtilEnt;
+import mineplex.core.common.util.UtilPlayer;
+import mineplex.core.common.util.UtilTime;
+import mineplex.game.clans.clans.worldevent.api.BossAbility;
+import mineplex.game.clans.clans.worldevent.boss.ironwizard.GolemCreature;
+
+public class GolemSpike extends BossAbility
+{
+ private static final int SPIKE_HEIGHT = 2;
+ private static final long ATTACK_DURATION = 1000 + (500 * SPIKE_HEIGHT * 2);
+ private static final long SPIKE_REMAIN = 1000;
+ private long _start;
+ private List