Implement Necromancer boss and give it some beginning attacks

This commit is contained in:
AlexTheCoder 2016-07-05 07:52:21 -04:00
parent b51ee4a066
commit cc7fc164bb
12 changed files with 1551 additions and 6 deletions

View File

@ -2,15 +2,16 @@ package mineplex.game.clans.clans.worldevent;
import java.lang.reflect.Constructor; 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.kinghill.KingHill;
import mineplex.game.clans.clans.worldevent.undead.UndeadCamp; import mineplex.game.clans.clans.worldevent.undead.UndeadCamp;
import mineplex.minecraft.game.classcombat.Skill.SkillFactory; import mineplex.minecraft.game.classcombat.Skill.SkillFactory;
import mineplex.minecraft.game.core.boss.WorldEvent; 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 public enum WorldEventType
{ {
@ -18,7 +19,8 @@ public enum WorldEventType
KING_OF_THE_HILL("King of The Hill", KingHill.class, 30), KING_OF_THE_HILL("King of The Hill", KingHill.class, 30),
UNDEAD_CAMP("Undead Camp", UndeadCamp.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); BROOD_MOTHER("Brood Mother", SpiderBoss.class, 30),
NECROMANCER("Necromancer", NecromancerBoss.class, 30);
private String _name; private String _name;
private Class<? extends WorldEvent> _clazz; private Class<? extends WorldEvent> _clazz;

View File

@ -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;
}
}

View File

@ -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<Skeleton>
{
private ArrayList<BossAbility> _currentAbilities = new ArrayList<BossAbility>();
private int _lastAbility;
private HashMap<Class, Long> _cooldowns = new HashMap<Class, Long>();
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<BossAbility> 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<Class, Integer> weight = new HashMap<Class, Integer>();
HashMap<Player, Double> dist = new HashMap<Player, Double>();
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<Player> 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<Player> 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<Class, Integer> 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<Player> getPlayers(HashMap<Player, Double> map, double maxDist)
{
return getPlayers(map, 0, maxDist);
}
private ArrayList<Player> getPlayers(final HashMap<Player, Double> map, double minDist, double maxDist)
{
ArrayList<Player> list = new ArrayList<Player>();
for (Player p : map.keySet())
{
if (map.get(p) >= minDist && map.get(p) <= maxDist)
{
list.add(p);
}
}
Collections.sort(list, new Comparator<Player>()
{
@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);
}
}
}

View File

@ -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<NecromancerCreature, Skeleton>
{
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<Integer, MinionType[]> _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();
}
}
}
}

View File

@ -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<NecromancerCreature, Skeleton>
{
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);
}
}
}

View File

@ -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<NecromancerCreature, Skeleton>
{
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");
}
}
}
}

View File

@ -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<NecromancerCreature, Skeleton>
{
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<Player> ordered, HashMap<Player, Double> 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<Player> getTargets()
{
Skeleton necromancer = getBoss().getEntity();
LinkedList<Player> selections = new LinkedList<>();
List<Player> targeted = Lists.newArrayList();
HashMap<Player, Double> 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);
}
}
}

View File

@ -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<NecromancerCreature, Skeleton>
{
private static final int WRAITH_AMOUNT = 4;
private static final double DISTANCE_FROM_NECROMANCER = 4;
private ConcurrentHashMap<WraithCreature, String> _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");
}
}
}
}

View File

@ -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<? extends EventCreature> _code;
private MinionType(Class<? extends EventCreature> 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;
}
}

View File

@ -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<Skeleton>
{
private static final int BARBED_LEVEL = 1;
private static final int LIFETIME = 40;
private HashSet<Projectile> _arrows = new HashSet<Projectile>();
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<Projectile> arrowIterator = _arrows.iterator(); arrowIterator.hasNext();)
{
Projectile arrow = arrowIterator.next();
if (arrow.isDead() || !arrow.isValid())
{
arrowIterator.remove();
}
}
}
}

View File

@ -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<Zombie>
{
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);
}
}

View File

@ -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<Zombie>
{
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);
}
}