/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Nov 24, 2014, 5:58:22 PM (GMT)]
*/
package vazkii.botania.common.entity;
import java.util.List;
import javax.annotation.Nonnull;
import com.google.common.base.Predicates;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.BlockLeaves;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import vazkii.botania.common.Botania;
import vazkii.botania.common.core.helper.Vector3;
import vazkii.botania.common.lib.LibObfuscation;
public class EntityMagicMissile extends EntityThrowable {
private static final String TAG_TIME = "time";
private static final DataParameter<Boolean> EVIL = EntityDataManager.createKey(EntityMagicMissile.class, DataSerializers.BOOLEAN);
private static final DataParameter<Integer> TARGET = EntityDataManager.createKey(EntityMagicMissile.class, DataSerializers.VARINT);
double lockX, lockY = -1, lockZ;
int time = 0;
public EntityMagicMissile(World world) {
super(world);
setSize(0F, 0F);
}
public EntityMagicMissile(EntityLivingBase thrower, boolean evil) {
this(thrower.world);
ReflectionHelper.setPrivateValue(EntityThrowable.class, this, thrower, LibObfuscation.THROWER);
setEvil(evil);
}
@Override
protected void entityInit() {
dataManager.register(EVIL, false);
dataManager.register(TARGET, 0);
}
public void setEvil(boolean evil) {
dataManager.set(EVIL, evil);
}
public boolean isEvil() {
return dataManager.get(EVIL);
}
public void setTarget(EntityLivingBase e) {
dataManager.set(TARGET, e == null ? -1 : e.getEntityId());
}
public EntityLivingBase getTargetEntity() {
int id = dataManager.get(TARGET);
Entity e = world.getEntityByID(id);
if(e != null && e instanceof EntityLivingBase)
return (EntityLivingBase) e;
return null;
}
@Override
public void onUpdate() {
double lastTickPosX = this.lastTickPosX;
double lastTickPosY = this.lastTickPosY;
double lastTickPosZ = this.lastTickPosZ;
super.onUpdate();
if(!world.isRemote && (!getTarget() || time > 40)) {
setDead();
return;
}
boolean evil = isEvil();
Vector3 thisVec = Vector3.fromEntityCenter(this);
Vector3 oldPos = new Vector3(lastTickPosX, lastTickPosY, lastTickPosZ);
Vector3 diff = thisVec.subtract(oldPos);
Vector3 step = diff.normalize().multiply(0.05);
int steps = (int) (diff.mag() / step.mag());
Vector3 particlePos = oldPos;
Botania.proxy.setSparkleFXCorrupt(evil);
for(int i = 0; i < steps; i++) {
Botania.proxy.sparkleFX(particlePos.x, particlePos.y, particlePos.z, 1F, evil ? 0F : 0.4F, 1F, 0.8F, 2);
if(world.rand.nextInt(steps) <= 1)
Botania.proxy.sparkleFX(particlePos.x + (Math.random() - 0.5) * 0.4, particlePos.y + (Math.random() - 0.5) * 0.4, particlePos.z + (Math.random() - 0.5) * 0.4, 1F, evil ? 0F : 0.4F, 1F, 0.8F, 2);
particlePos = particlePos.add(step);
}
Botania.proxy.setSparkleFXCorrupt(false);
EntityLivingBase target = getTargetEntity();
if(target != null) {
if(lockY == -1) {
lockX = target.posX;
lockY = target.posY;
lockZ = target.posZ;
}
Vector3 targetVec = evil ? new Vector3(lockX, lockY, lockZ) : Vector3.fromEntityCenter(target);
Vector3 diffVec = targetVec.subtract(thisVec);
Vector3 motionVec = diffVec.normalize().multiply(evil ? 0.5 : 0.6);
motionX = motionVec.x;
motionY = motionVec.y;
if(time < 10)
motionY = Math.abs(motionY);
motionZ = motionVec.z;
List<EntityLivingBase> targetList = world.getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(posX - 0.5, posY - 0.5, posZ - 0.5, posX + 0.5, posY + 0.5, posZ + 0.5));
if(targetList.contains(target) && target != null) {
EntityLivingBase thrower = getThrower();
if(thrower != null) {
EntityPlayer player = thrower instanceof EntityPlayer ? (EntityPlayer) thrower : null;
target.attackEntityFrom(player == null ? DamageSource.causeMobDamage(thrower) : DamageSource.causePlayerDamage(player), evil ? 12 : 7);
} else target.attackEntityFrom(DamageSource.GENERIC, evil ? 12 : 7);
setDead();
}
if(evil && diffVec.mag() < 1)
setDead();
}
time++;
}
@Override
public void writeEntityToNBT(NBTTagCompound cmp) {
super.writeEntityToNBT(cmp);
cmp.setInteger(TAG_TIME, time);
}
@Override
public void readEntityFromNBT(NBTTagCompound cmp) {
super.readEntityFromNBT(cmp);
time = cmp.getInteger(TAG_TIME);
}
public boolean getTarget() {
EntityLivingBase target = getTargetEntity();
if(target != null && target.getHealth() > 0 && !target.isDead && world.loadedEntityList.contains(target))
return true;
if(target != null)
setTarget(null);
double range = 12;
List entities = world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(posX - range, posY - range, posZ - range, posX + range, posY + range, posZ + range), Predicates.instanceOf(isEvil() ? EntityPlayer.class : IMob.class));
while(entities.size() > 0) {
Entity e = (Entity) entities.get(world.rand.nextInt(entities.size()));
if(!(e instanceof EntityLivingBase) || e.isDead) { // Just in case...
entities.remove(e);
continue;
}
target = (EntityLivingBase) e;
setTarget(target);
break;
}
return target != null;
}
@Override
protected void onImpact(@Nonnull RayTraceResult pos) {
switch (pos.typeOfHit) {
case BLOCK: {
Block block = world.getBlockState(pos.getBlockPos()).getBlock();
if(!(block instanceof BlockBush) && !(block instanceof BlockLeaves))
setDead();
break;
}
case ENTITY: {
if (pos.entityHit == getTargetEntity())
setDead();
break;
}
default: {
setDead();
break;
}
}
}
}