From cc7fc164bb447fc3e38b160a313787bc985aea6e Mon Sep 17 00:00:00 2001 From: AlexTheCoder Date: Tue, 5 Jul 2016 07:52:21 -0400 Subject: [PATCH] Implement Necromancer boss and give it some beginning attacks --- .../clans/worldevent/WorldEventType.java | 14 +- .../boss/necromancer/NecromancerBoss.java | 72 ++++ .../boss/necromancer/NecromancerCreature.java | 309 ++++++++++++++++++ .../abilities/NecromancerHellishFlood.java | 109 ++++++ .../abilities/NecromancerPulse.java | 104 ++++++ .../abilities/NecromancerSmite.java | 104 ++++++ .../abilities/NecromancerStrike.java | 167 ++++++++++ .../abilities/NecromancerWraithSummon.java | 193 +++++++++++ .../boss/necromancer/minion/MinionType.java | 36 ++ .../minion/UndeadArcherCreature.java | 196 +++++++++++ .../minion/UndeadWarriorCreature.java | 110 +++++++ .../necromancer/minion/WraithCreature.java | 143 ++++++++ 12 files changed, 1551 insertions(+), 6 deletions(-) create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerBoss.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerCreature.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerHellishFlood.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerPulse.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerSmite.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerStrike.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerWraithSummon.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/MinionType.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadArcherCreature.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadWarriorCreature.java create mode 100644 Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/WraithCreature.java 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 42e822bc7..566b7acf8 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 @@ -2,15 +2,16 @@ package mineplex.game.clans.clans.worldevent; import java.lang.reflect.Constructor; -import mineplex.minecraft.game.core.boss.ironwizard.GolemBoss; -import mineplex.minecraft.game.core.boss.slimeking.SlimeBoss; -import mineplex.minecraft.game.core.boss.spider.SpiderBoss; -import org.bukkit.Location; - import mineplex.game.clans.clans.worldevent.kinghill.KingHill; import mineplex.game.clans.clans.worldevent.undead.UndeadCamp; 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.necromancer.NecromancerBoss; +import mineplex.minecraft.game.core.boss.slimeking.SlimeBoss; +import mineplex.minecraft.game.core.boss.spider.SpiderBoss; + +import org.bukkit.Location; public enum WorldEventType { @@ -18,7 +19,8 @@ public enum WorldEventType 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), - BROOD_MOTHER("Brood Mother", SpiderBoss.class, 30); + BROOD_MOTHER("Brood Mother", SpiderBoss.class, 30), + NECROMANCER("Necromancer", NecromancerBoss.class, 30); private String _name; private Class _clazz; diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerBoss.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerBoss.java new file mode 100644 index 000000000..1684345f8 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerBoss.java @@ -0,0 +1,72 @@ +package mineplex.minecraft.game.core.boss.necromancer; + +import mineplex.core.blockrestore.BlockRestore; +import mineplex.core.disguise.DisguiseManager; +import mineplex.core.projectile.ProjectileManager; +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.EventState; +import mineplex.minecraft.game.core.boss.WorldEvent; +import mineplex.minecraft.game.core.boss.necromancer.minion.MinionType; +import mineplex.minecraft.game.core.condition.ConditionManager; +import mineplex.minecraft.game.core.damage.DamageManager; + +import org.bukkit.Bukkit; +import org.bukkit.Location; + +public class NecromancerBoss extends WorldEvent +{ + public NecromancerBoss(DamageManager damageManager, BlockRestore blockRestore, ConditionManager conditionManager, ProjectileManager projectileManager, Location cornerLocation) + { + super(DisguiseManager.INSTANCE, projectileManager, damageManager, blockRestore, conditionManager, "Necromancer", cornerLocation, + "schematic/Golem.schematic"); + } + + @Override + protected void customStart() + { + Bukkit.broadcastMessage("Custom Start"); + spawnNecromancer(getCenterLocation()); + setState(EventState.LIVE); + announceStart(); + } + + /** + * Check if this slime boss has been defeated + */ + private void checkDeath() + { + if (getCreatures().size() == 0) + { + setState(EventState.COMPLETE); + Bukkit.broadcastMessage("FINISHED!"); + } + } + + @Override + public void removeCreature(EventCreature creature) + { + super.removeCreature(creature); + + if (creature instanceof NecromancerCreature) + { + checkDeath(); + } + } + + public EventCreature spawnMinion(MinionType type, Location location) + { + EventCreature minionCreature = type.getNewInstance(this, location); + if (minionCreature != null) + { + registerCreature(minionCreature); + } + return minionCreature; + } + + private NecromancerCreature spawnNecromancer(Location location) + { + NecromancerCreature necromancerCreature = new NecromancerCreature(this, location, 2500); + registerCreature(necromancerCreature); + return necromancerCreature; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerCreature.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerCreature.java new file mode 100644 index 000000000..7aa78fc58 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/NecromancerCreature.java @@ -0,0 +1,309 @@ +package mineplex.minecraft.game.core.boss.necromancer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Random; + +import mineplex.core.common.events.EntityVelocityChangeEvent; +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.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.necromancer.abilities.NecromancerHellishFlood; +import mineplex.minecraft.game.core.boss.necromancer.abilities.NecromancerPulse; +import mineplex.minecraft.game.core.boss.necromancer.abilities.NecromancerSmite; +import mineplex.minecraft.game.core.boss.necromancer.abilities.NecromancerStrike; +import mineplex.minecraft.game.core.boss.necromancer.abilities.NecromancerWraithSummon; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.entity.Skeleton.SkeletonType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.inventory.ItemStack; + +public class NecromancerCreature extends EventCreature +{ + private ArrayList _currentAbilities = new ArrayList(); + private int _lastAbility; + private HashMap _cooldowns = new HashMap(); + private boolean _hasUsedWraiths = false; + + public NecromancerCreature(NecromancerBoss boss, Location location, double maxHealth) + { + super(boss, location, "Necromancer", true, maxHealth, Skeleton.class); + + spawnEntity(); + } + + @Override + protected void spawnCustom() + { + UtilEnt.Vegetate(getEntity()); + getEntity().setSkeletonType(SkeletonType.WITHER); + getEntity().getEquipment().setItemInHand(new ItemStack(Material.RECORD_6)); //Meridian Scepter + getEntity().getEquipment().setItemInHandDropChance(0.f); + } + + @Override + public void dieCustom() + { + endAbility(); + } + + private void endAbility() + { + for (BossAbility ability : _currentAbilities) + { + ability.setFinished(); + HandlerList.unregisterAll(ability); + } + + _currentAbilities.clear(); + } + + @EventHandler + public void onTick(UpdateEvent event) + { + if (event.getType() != UpdateType.TICK) + { + 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;// _currentAbility.getCooldown(); + + HandlerList.unregisterAll(ability); + System.out.print("Unregistered necromancer ability " + ability.getClass().getSimpleName()); + + _cooldowns.put(ability.getClass(), System.currentTimeMillis() + (ability.getCooldown() * 1000)); + } + else if (ability.inProgress()) + { + canDoNew = false; + _lastAbility = 20;// _currentAbility.getCooldown(); + } + } + + if (_lastAbility-- <= 0 && canDoNew && UtilBlock.solid(getEntity().getLocation().getBlock().getRelative(BlockFace.DOWN))) + { + HashMap weight = new HashMap(); + HashMap 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()) + { + {// Strike and Pulse + ArrayList players = getPlayers(dist, UtilMath.r(10) == 0 ? 10 : 6); + + if (!players.isEmpty()) + { + if (players.size() >= 4 && new Random().nextDouble() <= .45) + { + weight.put(NecromancerPulse.class, 998); + } + else + { + weight.put(NecromancerStrike.class, 6); + } + } + } + {// Smite + ArrayList players = getPlayers(dist, 10); + + if (!players.isEmpty()) + { + weight.put(NecromancerSmite.class, 6); + } + } + {//Hellish Flood + weight.put(NecromancerHellishFlood.class, 6); + } + if (getHealth() <= 90) + {// Wraith Summon + if (!_hasUsedWraiths) + { + weight.clear(); + weight.put(NecromancerWraithSummon.class, 999); + } + } + } + + for (BossAbility ability : _currentAbilities) + { + weight.remove(ability.getClass()); + } + + for (Class c : _cooldowns.keySet()) + { + if (_cooldowns.get(c) > System.currentTimeMillis()) + { + weight.remove(c); + } + } + + BossAbility ability = null; + + if (!weight.isEmpty()) + { + int i = 0; + + for (Integer entry : weight.values()) + { + i += entry; + } + + loop: for (int a = 0; a < 10; a++) + { + int luckyNumber = UtilMath.r(i); + + for (Entry entry : weight.entrySet()) + { + luckyNumber -= entry.getValue(); + + if (luckyNumber <= 0) + { + try + { + ability = (BossAbility) entry.getKey().getConstructor(NecromancerCreature.class).newInstance(this); + + if (ability.getTarget() == null || ability.hasFinished()) + { + ability = null; + } + else + { + break loop; + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + + break; + } + } + } + } + + if (ability != null && ability.getTarget() != null) + { + + Bukkit.getPluginManager().registerEvents(ability, getEvent().getPlugin()); + + System.out.print("Necromancer is using " + ability.getClass().getSimpleName()); + + if (ability instanceof NecromancerWraithSummon) + { + _hasUsedWraiths = true; + } + + _currentAbilities.add(ability); + } + + _lastAbility = 10; + } + + for (BossAbility ability : _currentAbilities) + { + ability.tick(); + } + } + + private ArrayList getPlayers(HashMap map, double maxDist) + { + return getPlayers(map, 0, maxDist); + } + + private ArrayList getPlayers(final HashMap map, double minDist, double maxDist) + { + ArrayList list = new ArrayList(); + + for (Player p : map.keySet()) + { + if (map.get(p) >= minDist && map.get(p) <= maxDist) + { + list.add(p); + } + } + + Collections.sort(list, new Comparator() + { + + @Override + public int compare(Player o1, Player o2) + { + return Double.compare(map.get(o2), map.get(o1)); + } + }); + + return list; + } + + @EventHandler + public void onNecromancerDamage(CustomDamageEvent event) + { + if (event.GetDamageeEntity().getEntityId() == getEntity().getEntityId()) + { + event.SetKnockback(false); + } + } + + @EventHandler + public void noFallDamage(CustomDamageEvent event) + { + if (getEntity() == null) + return; + + if (event.GetDamageeEntity().getEntityId() != getEntity().getEntityId()) + return; + + DamageCause cause = event.GetCause(); + + if (cause == DamageCause.FALL) + { + event.SetCancelled("Boss Invulnerability"); + } + } + + @EventHandler + public void onVelocity(EntityVelocityChangeEvent event) + { + if (event.getEntity().getEntityId() == getEntity().getEntityId()) + { + event.setCancelled(true); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerHellishFlood.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerHellishFlood.java new file mode 100644 index 000000000..832399221 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerHellishFlood.java @@ -0,0 +1,109 @@ +package mineplex.minecraft.game.core.boss.necromancer.abilities; + +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerBoss; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerCreature; +import mineplex.minecraft.game.core.boss.necromancer.minion.MinionType; + +import org.bukkit.Location; +import org.bukkit.entity.Skeleton; + +public class NecromancerHellishFlood extends BossAbility +{ + private static final int WAVE_COUNT = 3; + private static final int WAVE_SIZE = 5; + private static final MinionType[] POSSIBLE_MINIONS = new MinionType[] {MinionType.WARRIOR, MinionType.WRAITH}; + private static final long WAVE_DELAY = 1000; + + private ConcurrentHashMap _waves = new ConcurrentHashMap<>(); + private long _lastSpawned; + private int _current; + + public NecromancerHellishFlood(NecromancerCreature creature) + { + super(creature); + + if (WAVE_COUNT > 0) + { + for (int i = 1; i <= WAVE_COUNT; i++) + { + createWave(i); + } + } + _lastSpawned = System.currentTimeMillis(); + _current = 1; + } + + private void createWave(int number) + { + int length = POSSIBLE_MINIONS.length; + if (length <= 0 || WAVE_SIZE <= 0) + { + return; + } + MinionType[] wave = new MinionType[WAVE_SIZE]; + for (int i = 0; i < WAVE_SIZE; i++) + { + wave[i] = POSSIBLE_MINIONS[new Random().nextInt(length)]; + } + _waves.put(number, wave); + } + + @Override + public boolean canMove() + { + return false; + } + + @Override + public boolean inProgress() + { + return true; + } + + @Override + public boolean hasFinished() + { + return !_waves.isEmpty(); + } + + @Override + public void setFinished() + { + _waves.clear(); + } + + @Override + public void tick() + { + if (UtilTime.elapsed(_lastSpawned, WAVE_DELAY)) + { + if (_current <= _waves.size()) + { + for (MinionType type : _waves.get(_current)) + { + Location toSpawn = getLocation().clone(); + toSpawn.add(UtilMath.random(3, 6), 0, UtilMath.random(3, 6)); + + ((NecromancerBoss)getBoss().getEvent()).spawnMinion(type, toSpawn); + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, toSpawn, null, 0, 2, ViewDist.MAX); + UtilParticle.PlayParticleToAll(ParticleType.SMOKE, toSpawn, null, 0, 2, ViewDist.MAX); + } + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, getEntity().getLocation(), null, 0, 2, ViewDist.MAX); + UtilParticle.PlayParticleToAll(ParticleType.SMOKE, getEntity().getLocation(), null, 0, 2, ViewDist.MAX); + _waves.remove(_current); + _current++; + _lastSpawned = System.currentTimeMillis(); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerPulse.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerPulse.java new file mode 100644 index 000000000..426f1f93e --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerPulse.java @@ -0,0 +1,104 @@ +package mineplex.minecraft.game.core.boss.necromancer.abilities; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import mineplex.core.recharge.Recharge; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerCreature; + +import org.bukkit.GameMode; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; + +public class NecromancerPulse extends BossAbility +{ + private static final long TOTAL_ATTACK_DURATION = 3000; + private long _start, _lastIncrement; + private int _radius; + + public NecromancerPulse(NecromancerCreature creature) + { + super(creature); + _start = System.currentTimeMillis(); + _radius = 2; + _lastIncrement = System.currentTimeMillis(); + } + + private int getRadius() + { + return Math.min(6, _radius); + } + + @Override + public int getCooldown() + { + return 5; + } + + @Override + public boolean canMove() + { + return false; + } + + @Override + public boolean inProgress() + { + return true; + } + + @Override + public boolean hasFinished() + { + return UtilTime.elapsed(_start, TOTAL_ATTACK_DURATION); + } + + @Override + public void setFinished() + { + _start = System.currentTimeMillis() - TOTAL_ATTACK_DURATION; + } + + @Override + public void tick() + { + if (UtilTime.elapsed(_lastIncrement, 500)) + { + _lastIncrement = System.currentTimeMillis(); + _radius++; + } + + for (double token = 0; token <= (2 * Math.PI); token += .2) + { + double x = getRadius() * Math.cos(token); + double z = getRadius() * Math.sin(token); + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, getEntity().getLocation().add(x, 0.3, z), null, 0, 1, ViewDist.MAX); + } + + for (Player player : UtilPlayer.getInRadius(getEntity().getLocation(), getRadius()).keySet()) + { + if (player.isDead() || !player.isValid() || !player.isOnline()) + { + continue; + } + if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) + { + continue; + } + if (!Recharge.Instance.use(player, "Pulse Knockback", 400, false, false, false)) + { + continue; + } + + player.playSound(player.getLocation(), Sound.AMBIENCE_THUNDER, 1f, 1f); + UtilAction.velocity(player, UtilAlg.getTrajectory2d(getEntity(), player), .2, false, 0.6, 0, 1.4, true); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerSmite.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerSmite.java new file mode 100644 index 000000000..217dd7d68 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerSmite.java @@ -0,0 +1,104 @@ +package mineplex.minecraft.game.core.boss.necromancer.abilities; + +import java.math.BigDecimal; + +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilTime; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerCreature; + +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +public class NecromancerSmite extends BossAbility +{ + private static final long TOTAL_ATTACK_DURATION = 8000; + private long _start; + private int _ticks; + private boolean _shot; + + public NecromancerSmite(NecromancerCreature creature) + { + super(creature); + _start = System.currentTimeMillis(); + _ticks = 0; + _shot = false; + } + + @Override + public int getCooldown() + { + return 15; + } + + @Override + public boolean canMove() + { + return false; + } + + @Override + public boolean inProgress() + { + return true; + } + + @Override + public boolean hasFinished() + { + return UtilTime.elapsed(_start, TOTAL_ATTACK_DURATION) && _shot; + } + + @Override + public void setFinished() + { + _start = System.currentTimeMillis() - TOTAL_ATTACK_DURATION; + _shot = true; + } + + @Override + public void tick() + { + if (_shot) + return; + + if (_ticks < (6 * 20)) + { + _ticks++; + double maxHeight = Math.min(_ticks / 20, 6); + int radius = Math.max(6 - (new BigDecimal(_ticks).divide(new BigDecimal(20)).intValue()), 0); + + for (double y = 0; y < maxHeight; y += 0.5) + { + double cos = radius * Math.cos(y); + double sin = radius * Math.sin(y); + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, getEntity().getLocation().add(cos, y, sin), null, 0, 1, ViewDist.MAX); + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, getEntity().getLocation().add(sin, y, cos), null, 0, 1, ViewDist.MAX); + } + } + else + { + _shot = true; + for (Player player : UtilPlayer.getInRadius(getEntity().getLocation(), 10).keySet()) + { + if (player.isDead() || !player.isValid() || !player.isOnline()) + { + continue; + } + if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) + { + continue; + } + + player.getWorld().strikeLightningEffect(player.getLocation()); + getBoss().getEvent().getDamageManager().NewDamageEvent(player, getEntity(), null, DamageCause.LIGHTNING, 15 * getBoss().getDifficulty(), false, true, false, getEntity().getName(), "Lightning Strike"); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerStrike.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerStrike.java new file mode 100644 index 000000000..cb42fbeb5 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerStrike.java @@ -0,0 +1,167 @@ +package mineplex.minecraft.game.core.boss.necromancer.abilities; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilBlock; +import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilServer; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerCreature; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import com.google.common.collect.Lists; + +public class NecromancerStrike extends BossAbility +{ + private static final double MAX_RANGE = 10; + private static final Integer MAX_TARGETS = 3; + private boolean _shot; + + public NecromancerStrike(NecromancerCreature creature) + { + super(creature); + _shot = false; + } + + private int getPosition(Player toAdd, LinkedList ordered, HashMap 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 List getTargets() + { + Skeleton necromancer = getBoss().getEntity(); + LinkedList selections = new LinkedList<>(); + List targeted = Lists.newArrayList(); + + HashMap near = UtilPlayer.getInRadius(necromancer.getLocation(), MAX_RANGE); + + for (Player nearby : near.keySet()) + { + if (nearby.getGameMode() == GameMode.CREATIVE || nearby.getGameMode() == GameMode.SPECTATOR) + { + continue; + } + + if (selections.isEmpty()) + { + selections.addFirst(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)); + } + } + + return targeted; + } + + private void shootAt(Player target) + { + double curRange = 0; + boolean canHit = false; + + while (curRange <= MAX_RANGE) + { + Location newTarget = getEntity().getEyeLocation().add(UtilAlg.getTrajectory(getEntity(), target).multiply(curRange)); + + if (!UtilBlock.airFoliage(newTarget.getBlock())) + { + canHit = false; + break; + } + if (UtilMath.offset(newTarget, target.getLocation()) <= 0.7) + { + canHit = true; + break; + } + + curRange += 0.2; + + UtilParticle.PlayParticle(ParticleType.WITCH_MAGIC, newTarget, 0, 0, 0, 0, 1, + ViewDist.MAX, UtilServer.getPlayers()); + + canHit = true; + } + + if (canHit) + { + getBoss().getEvent().getDamageManager().NewDamageEvent(target, getEntity(), null, DamageCause.CUSTOM, 10 * getBoss().getDifficulty(), true, true, false, getEntity().getName(), "Mystical Energy"); + } + } + + @Override + public int getCooldown() + { + return 3; + } + + @Override + public boolean canMove() + { + return false; + } + + @Override + public boolean inProgress() + { + return false; + } + + @Override + public boolean hasFinished() + { + return _shot; + } + + @Override + public void setFinished() + { + _shot = true; + } + + @Override + public void tick() + { + if (_shot) + return; + + _shot = true; + + for (Player target : getTargets()) + { + shootAt(target); + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerWraithSummon.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerWraithSummon.java new file mode 100644 index 000000000..dc0b31e4f --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/abilities/NecromancerWraithSummon.java @@ -0,0 +1,193 @@ +package mineplex.minecraft.game.core.boss.necromancer.abilities; + +import java.util.concurrent.ConcurrentHashMap; + +import mineplex.core.common.util.F; +import mineplex.core.common.util.UtilParticle; +import mineplex.core.common.util.UtilPlayer; +import mineplex.core.common.util.UtilParticle.ParticleType; +import mineplex.core.common.util.UtilParticle.ViewDist; +import mineplex.minecraft.game.core.boss.BossAbility; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerBoss; +import mineplex.minecraft.game.core.boss.necromancer.NecromancerCreature; +import mineplex.minecraft.game.core.boss.necromancer.minion.MinionType; +import mineplex.minecraft.game.core.boss.necromancer.minion.WraithCreature; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.util.Vector; + +public class NecromancerWraithSummon extends BossAbility +{ + private static final int WRAITH_AMOUNT = 4; + private static final double DISTANCE_FROM_NECROMANCER = 4; + + private ConcurrentHashMap _wraiths = new ConcurrentHashMap<>(); + private Location[] _spawns; + + public NecromancerWraithSummon(NecromancerCreature creature) + { + super(creature); + + _spawns = new Location[] + { + getEntity().getLocation().add(DISTANCE_FROM_NECROMANCER, 0, DISTANCE_FROM_NECROMANCER), + getEntity().getLocation().add(DISTANCE_FROM_NECROMANCER * -1, 0, DISTANCE_FROM_NECROMANCER), + getEntity().getLocation().add(DISTANCE_FROM_NECROMANCER, 0, DISTANCE_FROM_NECROMANCER * -1), + getEntity().getLocation().add(DISTANCE_FROM_NECROMANCER * -1, 0, DISTANCE_FROM_NECROMANCER * -1) + }; + if (WRAITH_AMOUNT > 0) + { + for (int i = 0; i < WRAITH_AMOUNT; i++) + { + int spawnIndex = i; + if (spawnIndex >= _spawns.length) + { + spawnIndex = spawnIndex % _spawns.length; + } + spawnWraith(_spawns[spawnIndex], i + 1); + } + + for (Player player : UtilPlayer.getInRadius(getEntity().getLocation(), 80).keySet()) + { + if (player.isDead() || !player.isValid() || !player.isOnline()) + { + continue; + } + if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) + { + continue; + } + + player.sendMessage(F.main(getBoss().getEvent().getName(), "You must slay all " + WRAITH_AMOUNT + " wraiths before continuing to fight the Necromancer!")); + } + } + } + + private String getNumberString(Integer number) + { + String num = number.toString(); + char last = num.toCharArray()[num.length() - 1]; + + String formatted = number.toString(); + String ending = ""; + + if (last == '1' && !num.equals("1" + last)) + { + ending = "st"; + } + if (last == '2' && !num.equals("1" + last)) + { + ending = "nd"; + } + if (last == '3' && !num.equals("1" + last)) + { + ending = "rd"; + } + if (ending.equals("")) + { + ending = "th"; + } + + return formatted + ending; + } + + private void spawnWraith(Location loc, int number) + { + WraithCreature wraith = (WraithCreature)((NecromancerBoss)getBoss().getEvent()).spawnMinion(MinionType.WRAITH, loc); + _wraiths.put(wraith, getNumberString(number)); + } + + @Override + public int getCooldown() + { + return 9999; + } + + @Override + public boolean canMove() + { + return false; + } + + @Override + public boolean inProgress() + { + return true; + } + + @Override + public boolean hasFinished() + { + return !_wraiths.isEmpty(); + } + + @Override + public void setFinished() + { + for (WraithCreature wraith : _wraiths.keySet()) + { + wraith.remove(); + } + _wraiths.clear(); + } + + @Override + public void tick() + { + if (!hasFinished()) + { + int ticks = 10; + int hticks = 40; + boolean up = getEntity().getTicksLived() % (hticks * 2) < hticks; + int tick = getEntity().getTicksLived() % ticks; + double htick = getEntity().getTicksLived() % hticks; + int splits = 4; + + Location loc = getEntity().getLocation().add(0, 2, 0); + + for (double d = tick * (Math.PI * 2 / splits) / ticks; d < Math.PI * 2; d += Math.PI * 2 / splits) + { + Vector v = new Vector(Math.sin(d), 0, Math.cos(d)); + v.normalize().multiply(Math.max(0.2, Math.sin((htick / hticks) * Math.PI) * 1.0)); + v.setY((htick / hticks) * -2); + if (up) v.setY(-2 + 2 * (htick / hticks)); + + Location lloc = loc.clone().add(v); + + UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, lloc, null, 0f, 2, ViewDist.MAX); + } + } + } + + @EventHandler + public void onWraithDie(EntityDeathEvent event) + { + for (WraithCreature wraith : _wraiths.keySet()) + { + if (wraith.getEntity().equals(event.getEntity())) + { + Bukkit.broadcastMessage(F.main(getBoss().getEvent().getName(), "The " + _wraiths.remove(wraith) + " wraith has been slain!")); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onNecromancerDamage(CustomDamageEvent event) + { + if (event.GetDamageeEntity().equals(getBoss().getEntity())) + { + if (!hasFinished()) + { + event.SetCancelled("Wraiths Alive"); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/MinionType.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/MinionType.java new file mode 100644 index 000000000..269b83be9 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/MinionType.java @@ -0,0 +1,36 @@ +package mineplex.minecraft.game.core.boss.necromancer.minion; + +import java.lang.reflect.InvocationTargetException; + +import org.bukkit.Location; + +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.WorldEvent; + +public enum MinionType +{ + WARRIOR(UndeadWarriorCreature.class), + ARCHER(UndeadArcherCreature.class), + WRAITH(WraithCreature.class); + + private Class _code; + + private MinionType(Class code) + { + _code = code; + } + + public EventCreature getNewInstance(WorldEvent event, Location spawn) + { + try + { + return _code.getConstructor(WorldEvent.class, Location.class).newInstance(event, spawn); + } + catch (Exception e) + { + e.printStackTrace(); + } + + return null; + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadArcherCreature.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadArcherCreature.java new file mode 100644 index 000000000..cd40ddc23 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadArcherCreature.java @@ -0,0 +1,196 @@ +package mineplex.minecraft.game.core.boss.necromancer.minion; + +import java.util.HashSet; +import java.util.Iterator; + +import mineplex.core.common.util.UtilMath; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.WorldEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.entity.EntityShootBowEvent; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class UndeadArcherCreature extends EventCreature +{ + private static final int BARBED_LEVEL = 1; + private static final int LIFETIME = 40; + + private HashSet _arrows = new HashSet(); + + public UndeadArcherCreature(WorldEvent event, Location spawnLocation) + { + super(event, spawnLocation, "Undead Archer", true, 100, Skeleton.class); + + spawnEntity(); + } + + @Override + protected void spawnCustom() + { + Skeleton entity = getEntity(); + EntityEquipment eq = entity.getEquipment(); + eq.setItemInHand(new ItemStack(Material.BOW)); + eq.setHelmet(new ItemStack(Material.CHAINMAIL_HELMET)); + eq.setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); + eq.setLeggings(new ItemStack(Material.CHAINMAIL_LEGGINGS)); + eq.setBoots(new ItemStack(Material.CHAINMAIL_BOOTS)); + eq.setItemInHandDropChance(0.f); + eq.setHelmetDropChance(0.f); + eq.setChestplateDropChance(0.f); + eq.setLeggingsDropChance(0.f); + eq.setBootsDropChance(0.f); + entity.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 999999, 0)); + } + + @Override + public void dieCustom() + { + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + return; + } + + if (Math.random() > 0.97) + { + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.CHAINMAIL_HELMET)); + } + + if (Math.random() > 0.97) + { + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.CHAINMAIL_CHESTPLATE)); + } + + if (Math.random() > 0.97) + { + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.CHAINMAIL_LEGGINGS)); + } + + if (Math.random() > 0.97) + { + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.CHAINMAIL_BOOTS)); + } + + if (Math.random() > 0.90) + { + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.BOW)); + } + + getEntity().getWorld().dropItem(getEntity().getLocation(), new org.bukkit.inventory.ItemStack(Material.ARROW, UtilMath.r(12) + 1)); + + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.EMERALD, UtilMath.r(5) + 1)); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void bowShoot(EntityShootBowEvent event) + { + if (BARBED_LEVEL == 0) + { + return; + } + + if (!(event.getProjectile() instanceof Arrow)) + { + return; + } + + if (event.getEntity().getEntityId() != getEntity().getEntityId()) + { + return; + } + + _arrows.add((Projectile) event.getProjectile()); + } + + @EventHandler(priority = EventPriority.HIGH) + public void damage(CustomDamageEvent event) + { + if (event.IsCancelled()) + { + return; + } + + if (event.GetCause() != DamageCause.PROJECTILE) + { + return; + } + + Projectile projectile = event.GetProjectile(); + LivingEntity damagee = event.GetDamageeEntity(); + LivingEntity damager = event.GetDamagerEntity(true); + + if (projectile == null) + { + return; + } + + if (damagee == null) + { + return; + } + + if (damager == null) + { + return; + } + + // Level + if (BARBED_LEVEL == 0) + { + return; + } + + Player damageePlayer = event.GetDamageePlayer(); + + if (damageePlayer != null) + { + damageePlayer.setSprinting(false); + } + + // Damage + event.AddMod(damager.getName(), "Barbed Arrows", 0, false); + + // Condition + getEvent().getCondition().Factory().Slow("Barbed Arrows", damagee, damager, (projectile.getVelocity().length() / 3) * (2 + BARBED_LEVEL), 0, false, true, true, true); + } + + @EventHandler + public void clean(UpdateEvent event) + { + if (event.getType() != UpdateType.FAST) + { + return; + } + + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + remove(); + return; + } + + for (Iterator arrowIterator = _arrows.iterator(); arrowIterator.hasNext();) + { + Projectile arrow = arrowIterator.next(); + + if (arrow.isDead() || !arrow.isValid()) + { + arrowIterator.remove(); + } + } + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadWarriorCreature.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadWarriorCreature.java new file mode 100644 index 000000000..f568eaf94 --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/UndeadWarriorCreature.java @@ -0,0 +1,110 @@ +package mineplex.minecraft.game.core.boss.necromancer.minion; + +import mineplex.core.common.util.UtilAction; +import mineplex.core.common.util.UtilAlg; +import mineplex.core.common.util.UtilMath; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.WorldEvent; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class UndeadWarriorCreature extends EventCreature +{ + private static final int LIFETIME = 40; + + public UndeadWarriorCreature(WorldEvent event, Location spawnLocation) + { + super(event, spawnLocation, "Undead Warrior", true, 100, Zombie.class); + spawnEntity(); + } + + @Override + protected void spawnCustom() + { + Zombie entity = getEntity(); + EntityEquipment eq = entity.getEquipment(); + eq.setHelmet(new ItemStack(Material.IRON_HELMET)); + eq.setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); + eq.setLeggings(new ItemStack(Material.IRON_LEGGINGS)); + eq.setBoots(new ItemStack(Material.IRON_BOOTS)); + eq.setItemInHand(new ItemStack(Material.STONE_SWORD)); + eq.setHelmetDropChance(0.f); + eq.setChestplateDropChance(0.f); + eq.setLeggingsDropChance(0.f); + eq.setBootsDropChance(0.f); + eq.setItemInHandDropChance(0.f); + entity.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 999999, 0)); + } + + @Override + public void dieCustom() + { + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + return; + } + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.IRON_HELMET)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.IRON_CHESTPLATE)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.IRON_LEGGINGS)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.IRON_BOOTS)); + + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.EMERALD, UtilMath.r(5) + 1)); + } + + @EventHandler + public void leap(UpdateEvent event) + { + if (getEntity() == null) + return; + + if (event.getType() != UpdateType.FAST) + return; + + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + remove(); + return; + } + + if (Math.random() < 0.9) + return; + + Zombie zombie = getEntity(); + + if (zombie.getTarget() == null) + return; + + double dist = UtilMath.offset(zombie.getTarget(), zombie); + + if (dist <= 3 || dist > 16) + return; + + + double power = 0.8 + (1.2 * ((dist-3)/13d)); + + //Leap + UtilAction.velocity(zombie, UtilAlg.getTrajectory(zombie, zombie.getTarget()), + power, false, 0, 0.2, 1, true); + + //Effect + zombie.getWorld().playSound(zombie.getLocation(), Sound.ZOMBIE_HURT, 1f, 2f); + } +} \ No newline at end of file diff --git a/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/WraithCreature.java b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/WraithCreature.java new file mode 100644 index 000000000..eb7e2fefa --- /dev/null +++ b/Plugins/Mineplex.Minecraft.Game.Core/src/mineplex/minecraft/game/core/boss/necromancer/minion/WraithCreature.java @@ -0,0 +1,143 @@ +package mineplex.minecraft.game.core.boss.necromancer.minion; + +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.itemstack.ItemBuilder; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; +import mineplex.minecraft.game.core.boss.EventCreature; +import mineplex.minecraft.game.core.boss.WorldEvent; +import mineplex.minecraft.game.core.damage.CustomDamageEvent; + +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Zombie; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class WraithCreature extends EventCreature +{ + private static final int LIFETIME = -1; + + public WraithCreature(WorldEvent event, Location spawnLocation) + { + super(event, spawnLocation, "Wraith", true, 200, Zombie.class); + spawnEntity(); + } + + @Override + protected void spawnCustom() + { + Zombie entity = getEntity(); + EntityEquipment eq = entity.getEquipment(); + eq.setHelmet(new ItemStack(Material.SKULL_ITEM, 1, (short)1)); + eq.setChestplate(new ItemBuilder(Material.LEATHER_CHESTPLATE).setColor(Color.BLACK).build()); + eq.setLeggings(new ItemBuilder(Material.LEATHER_LEGGINGS).setColor(Color.BLACK).build()); + eq.setBoots(new ItemBuilder(Material.LEATHER_BOOTS).setColor(Color.BLACK).build()); + eq.setItemInHand(new ItemStack(Material.IRON_SWORD)); + eq.setHelmetDropChance(0.f); + eq.setChestplateDropChance(0.f); + eq.setLeggingsDropChance(0.f); + eq.setBootsDropChance(0.f); + eq.setItemInHandDropChance(0.f); + entity.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 999999, 0)); + entity.addPotionEffect(new PotionEffect(PotionEffectType.FIRE_RESISTANCE, 999999, 0)); + entity.addPotionEffect(new PotionEffect(PotionEffectType.WATER_BREATHING, 999999, 0)); + entity.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 999999, 1)); + } + + @Override + public void dieCustom() + { + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + return; + } + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.DIAMOND_HELMET)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.DIAMOND_CHESTPLATE)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.DIAMOND_LEGGINGS)); + + if (Math.random() > 0.97) + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.DIAMOND_BOOTS)); + + getEntity().getWorld().dropItem(getEntity().getLocation(), new ItemStack(Material.EMERALD, UtilMath.r(10) + 1)); + } + + @EventHandler(priority = EventPriority.HIGH) + public void damage(CustomDamageEvent event) + { + if (event.IsCancelled()) + { + return; + } + + LivingEntity damagee = event.GetDamageeEntity(); + LivingEntity damager = event.GetDamagerEntity(false); + + if (damagee == null) + { + return; + } + + if (damager == null) + { + return; + } + + // Damage + event.AddMod(damager.getName(), "Mystical Darkness", 2, false); + + // Condition + getEvent().getCondition().Factory().Poison("Mystical Darkness", damagee, damager, 5, 0, false, true, false); + } + + @EventHandler + public void blink(UpdateEvent event) + { + if (getEntity() == null) + return; + + if (event.getType() != UpdateType.FAST) + return; + + if (LIFETIME >= 0 && getEntity().getTicksLived() >= (20 * LIFETIME)) + { + remove(); + return; + } + + if (Math.random() < 0.6) + return; + + Zombie zombie = getEntity(); + + if (zombie.getTarget() == null) + return; + + double dist = UtilMath.offset(zombie.getTarget(), zombie); + + if (dist <= 10 || dist > 25) + return; + + UtilParticle.PlayParticleToAll(ParticleType.SMOKE, zombie.getLocation(), 0, 0, 0, 0, 5, ViewDist.MAX); + zombie.getWorld().playSound(zombie.getLocation(), Sound.ENDERMAN_TELEPORT, 1f, 2f); + zombie.teleport(zombie.getTarget().getLocation().add(UtilMath.random(0, 1.5), 0, UtilMath.random(0, 1.5))); + UtilParticle.PlayParticleToAll(ParticleType.SMOKE, zombie.getLocation(), 0, 0, 0, 0, 5, ViewDist.MAX); + zombie.getWorld().playSound(zombie.getLocation(), Sound.ENDERMAN_TELEPORT, 1f, 2f); + } +} \ No newline at end of file