/*******************************************************************************
* AbyssalCraft
* Copyright (c) 2012 - 2017 Shinoow.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Contributors:
* Shinoow - implementation
******************************************************************************/
package com.shinoow.abyssalcraft.common.entity.anti;
import net.minecraft.entity.Entity;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.entity.ai.EntityAIAvoidEntity;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
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.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.shinoow.abyssalcraft.api.entity.IAntiEntity;
import com.shinoow.abyssalcraft.common.entity.ai.EntityAIAntiCreeperSwell;
import com.shinoow.abyssalcraft.lib.ACConfig;
import com.shinoow.abyssalcraft.lib.ACLoot;
public class EntityAntiCreeper extends EntityMob implements IAntiEntity {
private static final DataParameter<Integer> STATE = EntityDataManager.<Integer>createKey(EntityAntiCreeper.class, DataSerializers.VARINT);
private static final DataParameter<Boolean> POWERED = EntityDataManager.<Boolean>createKey(EntityAntiCreeper.class, DataSerializers.BOOLEAN);
private static final DataParameter<Boolean> IGNITED = EntityDataManager.<Boolean>createKey(EntityAntiCreeper.class, DataSerializers.BOOLEAN);
/**
* Time when this creeper was last in an active state (Messed up code here, probably causes creeper animation to go
* weird)
*/
private int lastActiveTime;
/**
* The amount of time since the creeper was close enough to the player to ignite
*/
private int timeSinceIgnited;
private int fuseTime = 30;
/** Explosion radius for this creeper. */
private int explosionRadius = 10;
public EntityAntiCreeper(World par1World){
super(par1World);
tasks.addTask(1, new EntityAISwimming(this));
tasks.addTask(2, new EntityAIAntiCreeperSwell(this));
tasks.addTask(3, new EntityAIAvoidEntity(this, EntityOcelot.class, 6.0F, 1.0D, 1.2D));
tasks.addTask(4, new EntityAIAttackMelee(this, 1.0D, false));
tasks.addTask(5, new EntityAIWander(this, 0.8D));
tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
tasks.addTask(6, new EntityAILookIdle(this));
targetTasks.addTask(1, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true));
targetTasks.addTask(2, new EntityAIHurtByTarget(this, false));
}
@Override
protected void applyEntityAttributes()
{
super.applyEntityAttributes();
getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25D);
if(ACConfig.hardcoreMode) getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(80.0D);
else getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(40.0D);
}
@Override
public int getMaxFallHeight()
{
return getAttackTarget() == null ? 3 : 3 + (int)(getHealth() - 1.0F);
}
@Override
public void fall(float par1, float par2)
{
super.fall(par1, par2);
timeSinceIgnited = (int)(timeSinceIgnited + par1 * 1.5F);
if (timeSinceIgnited > fuseTime - 5)
timeSinceIgnited = fuseTime - 5;
}
@Override
protected void entityInit()
{
super.entityInit();
dataManager.register(STATE, Integer.valueOf(-1));
dataManager.register(POWERED, Boolean.valueOf(false));
dataManager.register(IGNITED, Boolean.valueOf(false));
}
@Override
public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeEntityToNBT(par1NBTTagCompound);
if (dataManager.get(POWERED).booleanValue())
par1NBTTagCompound.setBoolean("powered", true);
par1NBTTagCompound.setShort("Fuse", (short)fuseTime);
par1NBTTagCompound.setByte("ExplosionRadius", (byte)explosionRadius);
par1NBTTagCompound.setBoolean("ignited", hasIgnited());
}
@Override
public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readEntityFromNBT(par1NBTTagCompound);
dataManager.set(POWERED, Boolean.valueOf(par1NBTTagCompound.getBoolean("powered")));
if (par1NBTTagCompound.hasKey("Fuse", 99))
fuseTime = par1NBTTagCompound.getShort("Fuse");
if (par1NBTTagCompound.hasKey("ExplosionRadius", 99))
explosionRadius = par1NBTTagCompound.getByte("ExplosionRadius");
if (par1NBTTagCompound.getBoolean("ignited"))
ignite();
}
@Override
public void onUpdate()
{
if (isEntityAlive())
{
lastActiveTime = timeSinceIgnited;
if (hasIgnited())
setCreeperState(1);
int i = getCreeperState();
if (i > 0 && timeSinceIgnited == 0)
playSound(SoundEvents.ENTITY_CREEPER_PRIMED, 1.0F, 0.5F);
timeSinceIgnited += i;
if (timeSinceIgnited < 0)
timeSinceIgnited = 0;
if (timeSinceIgnited >= fuseTime)
{
timeSinceIgnited = fuseTime;
explode();
}
}
super.onUpdate();
}
@Override
protected SoundEvent getHurtSound()
{
return SoundEvents.ENTITY_CREEPER_HURT;
}
@Override
protected SoundEvent getDeathSound()
{
return SoundEvents.ENTITY_CREEPER_DEATH;
}
@Override
public void onDeath(DamageSource par1DamageSource)
{
super.onDeath(par1DamageSource);
if (par1DamageSource.getEntity() instanceof EntityAntiSkeleton)
{
int i = Item.getIdFromItem(Items.RECORD_13);
int j = Item.getIdFromItem(Items.RECORD_WAIT);
int k = i + rand.nextInt(j - i + 1);
dropItem(Item.getItemById(k), 1);
}
}
@Override
protected void collideWithEntity(Entity par1Entity)
{
if(!world.isRemote && par1Entity instanceof EntityCreeper){
boolean flag = world.getGameRules().getBoolean("mobGriefing");
world.createExplosion(this, posX, posY, posZ, 5, flag);
setDead();
}
else par1Entity.applyEntityCollision(this);
}
@Override
public boolean attackEntityAsMob(Entity par1Entity)
{
return true;
}
public boolean getPowered()
{
return dataManager.get(POWERED).booleanValue();
}
/**
* Params: (Float)Render tick. Returns the intensity of the creeper's flash when it is ignited.
*/
@SideOnly(Side.CLIENT)
public float getCreeperFlashIntensity(float par1)
{
return (lastActiveTime + (timeSinceIgnited - lastActiveTime) * par1) / (fuseTime - 2);
}
@Override
protected Item getDropItem()
{
return Items.GUNPOWDER;
}
@Override
protected ResourceLocation getLootTable(){
return ACLoot.ENTITY_ANTI_CREEPER;
}
/**
* Returns the current state of creeper, -1 is idle, 1 is 'in fuse'
*/
public int getCreeperState()
{
return dataManager.get(STATE).intValue();
}
/**
* Sets the state of creeper, -1 to idle and 1 to be 'in fuse'
*/
public void setCreeperState(int state)
{
dataManager.set(STATE, Integer.valueOf(state));
}
@Override
public void onStruckByLightning(EntityLightningBolt lightningBolt)
{
super.onStruckByLightning(lightningBolt);
dataManager.set(POWERED, Boolean.valueOf(true));
}
@Override
protected boolean processInteract(EntityPlayer player, EnumHand p_184645_2_)
{
ItemStack stack = player.getHeldItem(p_184645_2_);
if (!stack.isEmpty() && stack.getItem() == Items.FLINT_AND_STEEL)
{
world.playSound(player, posX, posY, posZ, SoundEvents.ITEM_FLINTANDSTEEL_USE, getSoundCategory(), 1.0F, rand.nextFloat() * 0.4F + 0.8F);
player.swingArm(p_184645_2_);
if (!world.isRemote)
{
ignite();
stack.damageItem(1, player);
return true;
}
}
return super.processInteract(player, p_184645_2_);
}
private void explode()
{
if (!world.isRemote){
boolean flag = world.getGameRules().getBoolean("mobGriefing");
float f = getPowered() ? 2.0F : 1.0F;
world.createExplosion(this, posX, posY, posZ, explosionRadius * f, flag);
setDead();
}
}
public boolean hasIgnited()
{
return dataManager.get(IGNITED).booleanValue();
}
public void ignite()
{
dataManager.set(IGNITED, Boolean.valueOf(true));
}
}