/**
Copyright (C) 2014 by jabelar
This file is part of jabelar's Minecraft Forge modding examples; as such,
you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
For a copy of the GNU General Public License see <http://www.gnu.org/licenses/>.
*/
package com.blogspot.jabelarminecraft.wildanimals.entities.serpents;
import net.minecraft.block.BlockColored;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIAttackOnCollide;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILeapAtTarget;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMate;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAIPanic;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityGhast;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.passive.EntityChicken;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
import com.blogspot.jabelarminecraft.wildanimals.entities.IModEntity;
import com.blogspot.jabelarminecraft.wildanimals.utilities.Utilities;
public class EntitySerpent extends EntityAnimal implements IModEntity
{
private NBTTagCompound syncDataCompound = new NBTTagCompound();
// good to have instances of AI so task list can be modified, including in sub-classes
protected EntityAIBase aiSwimming = new EntityAISwimming(this);
protected EntityAIBase aiLeapAtTarget = new EntityAILeapAtTarget(this, 0.4F);
protected EntityAIBase aiAttackOnCollide = new EntityAIAttackOnCollide(this, 1.0D, true);
protected EntityAIBase aiMate = new EntityAIMate(this, 1.0D);
protected EntityAIBase aiWander = new EntityAIWander(this, 1.0D);
protected EntityAIBase aiWatchClosest = new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F);
protected EntityAIBase aiLookIdle = new EntityAILookIdle(this);
protected EntityAIBase aiHurtByTarget = new EntityAIHurtByTarget(this, true);
protected EntityAIBase aiPanic = new EntityAIPanic(this, 2.0D);
protected final EntityAIBase aiTargetChicken = new EntityAINearestAttackableTarget(this, EntityChicken.class, 200, false);
private float field_70926_e;
// use fields for sounds to allow easy changes in child classes
protected String soundHurt = "wildanimals:mob.serpent.death";
protected String soundDeath = "wildanimals:mob.serpent.death";
protected String soundCall = "wildanimals:mob.serpent.hiss";
public EntitySerpent(World par1World)
{
super(par1World);
// DEBUG
System.out.println("EntitySerpent constructor(), "+"on Client="
+par1World.isRemote+", EntityID = "+getEntityId()+", ModEntityID = "+entityUniqueID);
setSize(1.0F, 0.25F);
initSyncDataCompound();
setupAI();
}
// use clear tasks for subclasses then build up their ai task list specifically
@Override
public void clearAITasks()
{
tasks.taskEntries.clear();
targetTasks.taskEntries.clear();
}
@Override
public void setupAI()
{
getNavigator().setAvoidsWater(true);
clearAITasks(); // clear any tasks assigned in super classes
tasks.addTask(1, aiSwimming);
tasks.addTask(2, aiPanic);
tasks.addTask(3, aiLeapAtTarget);
tasks.addTask(4, aiAttackOnCollide);
tasks.addTask(5, aiMate);
tasks.addTask(6, aiWander);
tasks.addTask(7, aiWatchClosest);
tasks.addTask(8, aiLookIdle);
targetTasks.addTask(9, aiHurtByTarget);
targetTasks.addTask(10, aiTargetChicken);
}
// you don't have to call this as it is called automatically during entityLiving subclass creation
@Override
protected void applyEntityAttributes()
{
super.applyEntityAttributes();
getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.2D);
getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(8.0D);
}
/**
* Returns true if the newer Entity AI code should be run
*/
@Override
public boolean isAIEnabled()
{
return true;
}
/**
* Sets the active target the Task system uses for tracking
*/
@Override
public void setAttackTarget(EntityLivingBase par1EntityLivingBase)
{
super.setAttackTarget(par1EntityLivingBase);
}
/**
* main AI tick function, replaces updateEntityActionState
*/
@Override
protected void updateAITick()
{
dataWatcher.updateObject(18, Float.valueOf(getHealth()));
}
@Override
protected void entityInit()
{
super.entityInit();
dataWatcher.addObject(18, new Float(getHealth()));
dataWatcher.addObject(19, new Byte((byte)0));
dataWatcher.addObject(20, new Byte((byte)BlockColored.func_150032_b(1)));
}
// @Override
// // play step sound
// protected void func_145780_a(int p_145780_1_, int p_145780_2_, int p_145780_3_, Block p_145780_4_)
// {
// // serpents are silent when moving
// }
/**
* (abstract) Protected helper method to write subclass entity data to NBT.
*/
@Override
public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeEntityToNBT(par1NBTTagCompound);
// store additional custom variables for save, example: par1NBTTagCompound.setBoolean("Angry", isAngry());
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
@Override
public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readEntityFromNBT(par1NBTTagCompound);
// retrieve additional custom variables from save, example: setAngry(par1NBTTagCompound.getBoolean("Angry"));
}
/**
* Returns the sound this mob makes while it's alive.
*/
@Override
protected String getLivingSound()
{
return soundCall;
}
/**
* Returns the sound this mob makes when it is hurt.
*/
@Override
protected String getHurtSound()
{
return soundHurt;
}
/**
* Returns the sound this mob makes on death.
*/
@Override
protected String getDeathSound()
{
return soundDeath;
}
/**
* Returns the volume for the sounds this mob makes.
*/
@Override
protected float getSoundVolume()
{
return 0.3F;
}
@Override
protected Item getDropItem()
{
return Item.getItemById(-1);
}
/**
* Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
* use this to react to sunlight and start to burn.
*/
@Override
public void onLivingUpdate()
{
super.onLivingUpdate();
}
/**
* Called to update the entity's position/logic.
*/
@Override
public void onUpdate()
{
super.onUpdate();
if (func_70922_bv())
{
field_70926_e += (1.0F - field_70926_e) * 0.4F;
}
else
{
field_70926_e += (0.0F - field_70926_e) * 0.4F;
}
if (func_70922_bv())
{
numTicksToChaseTarget = 10;
}
if (isWet())
{
// can do special things if in water (or in rain)
}
else
{
}
}
/**
* Called when the entity is attacked.
*/
@Override
public boolean attackEntityFrom(DamageSource par1DamageSource, float par2)
{
if (isEntityInvulnerable())
{
return false;
}
else
{
Entity entity = par1DamageSource.getEntity();
// if (entity != null && !(entity instanceof EntityPlayer) && !(entity instanceof EntityArrow))
// {
// par2 = (par2 + 1.0F) / 2.0F;
// }
return super.attackEntityFrom(par1DamageSource, par2);
}
}
@Override
public boolean attackEntityAsMob(Entity par1Entity)
{
int i = 2;
return par1Entity.attackEntityFrom(DamageSource.causeMobDamage(this), i);
}
/**
* Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
*/
@Override
public boolean interact(EntityPlayer par1EntityPlayer)
{
// DEBUG
System.out.println("EntitySerpent interact()");
par1EntityPlayer.inventory.getCurrentItem();
return super.interact(par1EntityPlayer);
}
/**
* Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on
* the animal type)
*/
@Override
public boolean isBreedingItem(ItemStack par1ItemStack)
{
return par1ItemStack == null ? false : (!(par1ItemStack.getItem() instanceof ItemFood) ? false : ((ItemFood)par1ItemStack.getItem()).isWolfsFavoriteMeat());
}
/**
* Will return how many at most can spawn in a chunk at once.
*/
@Override
public int getMaxSpawnedInChunk()
{
return 8;
}
@Override
public EntitySerpent createChild(EntityAgeable par1EntityAgeable)
{
// DEBUG
System.out.println("EntitySerpent createChild()");
EntitySerpent entitySerpent = new EntitySerpent(worldObj);
// transfer any attributes from parent to child here, if desired (like owner for tamed entities)
return entitySerpent;
}
public void func_70918_i(boolean par1)
{
if (par1)
{
dataWatcher.updateObject(19, Byte.valueOf((byte)1));
}
else
{
dataWatcher.updateObject(19, Byte.valueOf((byte)0));
}
}
/**
* Returns true if the mob is currently able to mate with the specified mob.
*/
@Override
public boolean canMateWith(EntityAnimal par1EntityAnimal)
{
if (par1EntityAnimal == this)
{
return false;
}
else if (!(par1EntityAnimal instanceof EntitySerpent))
{
return false;
}
else
{
EntitySerpent entitySerpent = (EntitySerpent)par1EntityAnimal;
return (isInLove() && entitySerpent.isInLove());
}
}
public boolean func_70922_bv()
{
return dataWatcher.getWatchableObjectByte(19) == 1;
}
/**
* Determines if an entity can be despawned, used on idle far away entities
*/
@Override
protected boolean canDespawn()
{
return ticksExisted > 2400;
}
public boolean func_142018_a(EntityLivingBase par1EntityLivingBase, EntityLivingBase par2EntityLivingBase)
{
if (!(par1EntityLivingBase instanceof EntityCreeper) && !(par1EntityLivingBase instanceof EntityGhast))
{
return par1EntityLivingBase instanceof EntityPlayer && par2EntityLivingBase instanceof EntityPlayer && !((EntityPlayer)par2EntityLivingBase).canAttackPlayer((EntityPlayer)par1EntityLivingBase) ? false : !(par1EntityLivingBase instanceof EntityHorse) || !((EntityHorse)par1EntityLivingBase).isTame();
}
else
{
return false;
}
}
// *****************************************************
// ENCAPSULATION SETTER AND GETTER METHODS
// Don't forget to send sync packets in setters
// *****************************************************
@Override
public void setScaleFactor(float parScaleFactor)
{
syncDataCompound.setFloat("scaleFactor", Math.abs(parScaleFactor));
// don't forget to sync client and server
sendEntitySyncPacket();
}
@Override
public float getScaleFactor()
{
return syncDataCompound.getFloat("scaleFactor");
}
@Override
public void sendEntitySyncPacket()
{
Utilities.sendEntitySyncPacketToClient(this);
}
@Override
public NBTTagCompound getSyncDataCompound()
{
return syncDataCompound;
}
@Override
public void setSyncDataCompound(NBTTagCompound parCompound)
{
syncDataCompound = parCompound;
}
/* (non-Javadoc)
* @see com.blogspot.jabelarminecraft.wildanimals.entities.IModEntity#initSyncDataCompound()
*/
@Override
public void initSyncDataCompound()
{
syncDataCompound.setFloat("scaleFactor", 1.0F);
}
}