package com.nisovin.magicspells.spells.buff;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import org.bukkit.Location;
import org.bukkit.entity.Creature;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.spells.BuffSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.Util;
public class MinionSpell extends BuffSpell {
private EntityType[] creatureTypes;
private int[] chances;
private boolean preventCombust;
private boolean targetPlayers;
private HashMap<String,LivingEntity> minions;
private HashMap<String,LivingEntity> targets;
private Random random;
public MinionSpell(MagicConfig config, String spellName) {
super(config, spellName);
List<String> c = getConfigStringList("mob-chances", null);
if (c == null) {
c = new ArrayList<String>();
}
if (c.size() == 0) {
c.add("Zombie 100");
}
creatureTypes = new EntityType[c.size()];
chances = new int[c.size()];
for (int i = 0; i < c.size(); i++) {
String[] data = c.get(i).split(" ");
EntityType creatureType = Util.getEntityType(data[0]);
int chance = 0;
if (creatureType != null) {
try {
chance = Integer.parseInt(data[1]);
} catch (NumberFormatException e) {
}
}
creatureTypes[i] = creatureType;
chances[i] = chance;
}
preventCombust = getConfigBoolean("prevent-sun-burn", true);
targetPlayers = getConfigBoolean("target-players", false);
minions = new HashMap<String,LivingEntity>();
targets = new HashMap<String,LivingEntity>();
random = new Random();
}
@Override
public boolean castBuff(Player player, float power, String[] args) {
EntityType creatureType = null;
int num = random.nextInt(100);
int n = 0;
for (int i = 0; i < creatureTypes.length; i++) {
if (num < chances[i] + n) {
creatureType = creatureTypes[i];
break;
} else {
n += chances[i];
}
}
if (creatureType != null) {
// get spawn location
Location loc = null;
loc = player.getLocation();
loc.setX(loc.getX()-1);
// spawn creature
LivingEntity minion = (LivingEntity)player.getWorld().spawnEntity(loc, creatureType);
if (minion instanceof Creature) {
minions.put(player.getName(), minion);
targets.put(player.getName(), null);
} else {
minion.remove();
MagicSpells.error("Cannot summon a non-creature with the minion spell!");
return false;
}
} else {
// fail -- no creature found
return false;
}
return true;
}
@EventHandler
public void onEntityTarget(EntityTargetEvent event) {
if (!event.isCancelled() && minions.size() > 0 ) {
if (event.getTarget() != null && event.getTarget() instanceof Player) {
// a monster is trying to target a player
Player player = (Player)event.getTarget();
LivingEntity minion = minions.get(player.getName());
if (minion != null && minion.getEntityId() == event.getEntity().getEntityId()) {
// the targeted player owns the minion
if (isExpired(player)) {
// spell is expired
turnOff(player);
return;
}
// check if the player has a current target
LivingEntity target = targets.get(player.getName());
if (target != null) {
// player has a target
if (target.isDead()) {
// the target is dead, so remove that target
targets.put(player.getName(), null);
event.setCancelled(true);
} else {
// send the minion after the player's target
event.setTarget(target);
MagicSpells.getVolatileCodeHandler().setTarget(minion, target);
addUse(player);
chargeUseCost(player);
}
} else {
// player doesn't have a target, so just order the minion to follow
event.setCancelled(true);
double distSq = minion.getLocation().toVector().distanceSquared(player.getLocation().toVector());
if (distSq > 3*3) {
// minion is too far, tell him to move closer
MagicSpells.getVolatileCodeHandler().entityPathTo(minion, player);
}
}
} else if (!targetPlayers && minions.containsValue(event.getEntity())) {
// player doesn't own minion, but it is an owned minion and pvp is off, so cancel
event.setCancelled(true);
}
} else if (event.getReason() == TargetReason.FORGOT_TARGET && minions.containsValue(event.getEntity())) {
// forgetting target but it's a minion, don't let them do that! (probably a spider going passive)
event.setCancelled(true);
}
}
}
@EventHandler
public void onEntityDeath(EntityDeathEvent event) {
if (minions.containsValue(event.getEntity())) {
event.setDroppedExp(0);
event.getDrops().clear();
}
}
@EventHandler
public void onEntityDamage(EntityDamageEvent event) {
if (!event.isCancelled() && event instanceof EntityDamageByEntityEvent && event.getEntity() instanceof LivingEntity) {
EntityDamageByEntityEvent evt = (EntityDamageByEntityEvent)event;
Player p = null;
if (evt.getDamager() instanceof Player) {
p = (Player)evt.getDamager();
} else if (evt.getDamager() instanceof Projectile && ((Projectile)evt.getDamager()).getShooter() instanceof Player) {
p = (Player)((Projectile)evt.getDamager()).getShooter();
}
if (p != null) {
if (minions.containsKey(p.getName())) {
if (isExpired(p)) {
turnOff(p);
return;
}
LivingEntity target = (LivingEntity)event.getEntity();
MagicSpells.getVolatileCodeHandler().setTarget(minions.get(p.getName()), target);
targets.put(p.getName(), target);
addUse(p);
chargeUseCost(p);
}
}
}
}
@EventHandler
public void onEntityCombust(EntityCombustEvent event) {
if (preventCombust && !event.isCancelled() && minions.containsValue(event.getEntity())) {
event.setCancelled(true);
}
}
@Override
public void turnOffBuff(Player player) {
LivingEntity minion = minions.remove(player.getName());
if (minion != null && !minion.isDead()) {
minion.setHealth(0);
}
targets.remove(player.getName());
}
@Override
protected void turnOff() {
for (LivingEntity minion : minions.values()) {
minion.setHealth(0);
}
minions.clear();
targets.clear();
}
@Override
public boolean isActive(Player player) {
return minions.containsKey(player.getName());
}
}