package com.nisovin.magicspells.spells.targeted;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.World;
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.util.Vector;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.events.SpellApplyDamageEvent;
import com.nisovin.magicspells.mana.ManaChangeReason;
import com.nisovin.magicspells.spelleffects.EffectPosition;
import com.nisovin.magicspells.spells.SpellDamageSpell;
import com.nisovin.magicspells.spells.TargetedEntitySpell;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.util.ExperienceUtils;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.SpellAnimation;
import com.nisovin.magicspells.util.TargetInfo;
public class DrainlifeSpell extends TargetedSpell implements TargetedEntitySpell, SpellDamageSpell {
private String takeType;
private double takeAmt;
private String giveType;
private double giveAmt;
private String spellDamageType;
private boolean showSpellEffect;
private int animationSpeed;
private boolean instant;
private boolean ignoreArmor;
private boolean checkPlugins;
public DrainlifeSpell(MagicConfig config, String spellName) {
super(config, spellName);
takeType = getConfigString("take-type", "health");
takeAmt = getConfigFloat("take-amt", 2);
giveType = getConfigString("give-type", "health");
giveAmt = getConfigFloat("give-amt", 2);
spellDamageType = getConfigString("spell-damage-type", "");
showSpellEffect = getConfigBoolean("show-spell-effect", true);
animationSpeed = getConfigInt("animation-speed", 2);
instant = getConfigBoolean("instant", true);
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);
} else {
boolean drained = drain(player, target.getTarget(), target.getPower());
if (!drained) {
return noTarget(player);
} else {
sendMessages(player, target.getTarget());
return PostCastAction.NO_MESSAGES;
}
}
}
return PostCastAction.HANDLE_NORMALLY;
}
@Override
public String getSpellDamageType() {
return spellDamageType;
}
private boolean drain(Player player, LivingEntity target, float power) {
double take = takeAmt * power;
double give = giveAmt * power;
// drain from target
if (takeType.equals("health")) {
if (target instanceof Player && checkPlugins) {
EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(player, target, DamageCause.ENTITY_ATTACK, take);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
take = event.getDamage();
player.setLastDamageCause(event);
}
SpellApplyDamageEvent event = new SpellApplyDamageEvent(this, player, target, take, DamageCause.MAGIC, spellDamageType);
Bukkit.getPluginManager().callEvent(event);
take = event.getFinalDamage();
if (ignoreArmor) {
double health = target.getHealth();
if (health > target.getMaxHealth()) health = target.getMaxHealth();
health -= take;
if (health < 0) health = 0;
if (health > target.getMaxHealth()) health = target.getMaxHealth();
if (health == 0 && player != null) {
MagicSpells.getVolatileCodeHandler().setKiller(target, player);
}
target.setHealth(health);
target.playEffect(EntityEffect.HURT);
} else {
target.damage(take, player);
}
} else if (takeType.equals("mana")) {
if (target instanceof Player) {
boolean removed = MagicSpells.getManaHandler().removeMana((Player)target, (int)Math.round(take), ManaChangeReason.OTHER);
if (!removed) {
give = 0;
}
}
} else if (takeType.equals("hunger")) {
if (target instanceof Player) {
Player p = (Player)target;
int food = p.getFoodLevel();
if (give > food) give = food;
food -= take;
if (food < 0) food = 0;
p.setFoodLevel(food);
}
} else if (takeType.equals("experience")) {
if (target instanceof Player) {
Player p = (Player)target;
int exp = ExperienceUtils.getCurrentExp(p);
if (give > exp) give = exp;
ExperienceUtils.changeExp(p, (int)Math.round(-take));
}
}
// give to caster
if (instant) {
giveToCaster(player, give);
playSpellEffects(player, target);
} else {
playSpellEffects(EffectPosition.TARGET, target);
}
// show animation
if (showSpellEffect) {
new DrainlifeAnim(target.getLocation(), player, give, power);
}
return true;
}
private void giveToCaster(Player player, double give) {
if (giveType.equals("health")) {
double h = player.getHealth() + give;
if (h > player.getMaxHealth()) h = player.getMaxHealth();
player.setHealth(h);
} else if (giveType.equals("mana")) {
MagicSpells.getManaHandler().addMana(player, (int)give, ManaChangeReason.OTHER);
} else if (giveType.equals("hunger")) {
int food = player.getFoodLevel();
food += give;
if (food > 20) food = 20;
player.setFoodLevel(food);
} else if (giveType.equals("experience")) {
ExperienceUtils.changeExp(player, (int)give);
}
}
@Override
public boolean castAtEntity(Player caster, LivingEntity target, float power) {
if (!validTargetList.canTarget(caster, target)) {
return false;
} else {
return drain(caster, target, power);
}
}
@Override
public boolean castAtEntity(LivingEntity target, float power) {
return false;
}
private class DrainlifeAnim extends SpellAnimation {
Vector current;
Player caster;
World world;
double giveAmt;
int range;
public DrainlifeAnim(Location start, Player caster, double giveAmt, float power) {
super(animationSpeed, true);
this.current = start.toVector();
this.caster = caster;
this.world = caster.getWorld();
this.giveAmt = giveAmt;
this.range = getRange(power);
}
@Override
protected void onTick(int tick) {
Vector targetVector = caster.getLocation().toVector();
Vector tempVector = current.clone();
tempVector.subtract(caster.getLocation().toVector()).normalize();
current.subtract(tempVector);
world.playEffect(current.toLocation(world), Effect.SMOKE, 4);
if (current.distanceSquared(targetVector) < 4 || tick > range * 1.5) {
stop();
if (!instant) {
giveToCaster(caster, giveAmt);
playSpellEffects(EffectPosition.CASTER, caster);
}
}
}
}
}