package com.nisovin.magicspells.spells.targeted; import java.util.ArrayList; import java.util.List; import org.bukkit.Bukkit; import org.bukkit.EntityEffect; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.material.MaterialData; import org.bukkit.util.Vector; import com.nisovin.magicspells.MagicSpells; import com.nisovin.magicspells.materials.MagicBlockMaterial; import com.nisovin.magicspells.materials.MagicMaterial; import com.nisovin.magicspells.spelleffects.EffectPosition; import com.nisovin.magicspells.spells.TargetedEntitySpell; import com.nisovin.magicspells.spells.TargetedSpell; import com.nisovin.magicspells.util.MagicConfig; import com.nisovin.magicspells.util.SpellAnimation; import com.nisovin.magicspells.util.TargetInfo; import com.nisovin.magicspells.util.Util; public class GeyserSpell extends TargetedSpell implements TargetedEntitySpell { private double damage; private double velocity; private int tickInterval; private int geyserHeight; private MagicMaterial geyserType; private boolean ignoreArmor; private boolean checkPlugins; public GeyserSpell(MagicConfig config, String spellName) { super(config, spellName); damage = getConfigFloat("damage", 0); velocity = getConfigInt("velocity", 10) / 10.0D; tickInterval = getConfigInt("animation-speed", 2); geyserHeight = getConfigInt("geyser-height", 4); String s = getConfigString("geyser-type", "water"); if (s.equalsIgnoreCase("lava")) { geyserType = new MagicBlockMaterial(new MaterialData(Material.STATIONARY_LAVA)); } else if (s.equalsIgnoreCase("water")) { geyserType = new MagicBlockMaterial(new MaterialData(Material.STATIONARY_WATER)); } else { geyserType = MagicSpells.getItemNameResolver().resolveBlock(s); } ignoreArmor = getConfigBoolean("ignore-armor", false); checkPlugins = getConfigBoolean("check-plugins", true); } @Override public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) { if (state == SpellCastState.NORMAL) { TargetInfo<LivingEntity> target = getTargetedEntity(player, power); if (target == null) { // fail -- no target return noTarget(player); } // do geyser action + animation boolean ok = geyser(player, target.getTarget(), target.getPower()); if (!ok) { return noTarget(player); } playSpellEffects(player, target.getTarget()); sendMessages(player, target.getTarget()); return PostCastAction.NO_MESSAGES; } return PostCastAction.HANDLE_NORMALLY; } private boolean geyser(Player caster, LivingEntity target, float power) { double dam = damage * power; // check plugins if (caster != null && target instanceof Player && checkPlugins && damage > 0) { EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(caster, target, DamageCause.ENTITY_ATTACK, dam); Bukkit.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return false; } dam = event.getDamage(); } // do damage and launch target if (dam > 0) { if (ignoreArmor) { double health = target.getHealth() - dam; if (health < 0) health = 0; target.setHealth(health); target.playEffect(EntityEffect.HURT); } else { if (caster != null) { target.damage(dam, caster); } else { target.damage(dam); } } } // launch target into air if (velocity > 0) { target.setVelocity(new Vector(0, velocity*power, 0)); } // create animation if (geyserHeight > 0) { List<Entity> allNearby = target.getNearbyEntities(50, 50, 50); allNearby.add(target); List<Player> playersNearby = new ArrayList<Player>(); for (Entity e : allNearby) { if (e instanceof Player) { playersNearby.add((Player)e); } } new GeyserAnimation(target.getLocation(), playersNearby); } return true; } @Override public boolean castAtEntity(Player caster, LivingEntity target, float power) { if (!validTargetList.canTarget(caster, target)) { return false; } else { geyser(caster, target, power); playSpellEffects(caster, target); return true; } } @Override public boolean castAtEntity(LivingEntity target, float power) { if (!validTargetList.canTarget(target)) { return false; } else { geyser(null, target, power); playSpellEffects(EffectPosition.TARGET, target); return true; } } private class GeyserAnimation extends SpellAnimation { private Location start; private List<Player> nearby; public GeyserAnimation(Location start, List<Player> nearby) { super(0, tickInterval, true); this.start = start; this.nearby = nearby; } @Override protected void onTick(int tick) { if (tick > geyserHeight*2) { stop(); } else if (tick < geyserHeight) { Block block = start.clone().add(0,tick,0).getBlock(); if (block.getType() == Material.AIR) { for (Player p : nearby) { Util.sendFakeBlockChange(p, block, geyserType); } } } else { int n = geyserHeight-(tick-geyserHeight)-1; // top to bottom Block block = start.clone().add(0, n, 0).getBlock(); for (Player p : nearby) { Util.restoreFakeBlockChange(p, block); } } } } }