base mod created
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
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.nbt.NBTTagList;
|
||||
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.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackDataLists;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class AbstractChestHorse extends AbstractHorse
|
||||
{
|
||||
private static final DataParameter<Boolean> DATA_ID_CHEST = EntityDataManager.<Boolean>createKey(AbstractChestHorse.class, DataSerializers.BOOLEAN);
|
||||
|
||||
public AbstractChestHorse(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.canGallop = false;
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(DATA_ID_CHEST, Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue((double)this.getModifiedMaxHealth());
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.17499999701976776D);
|
||||
this.getEntityAttribute(JUMP_STRENGTH).setBaseValue(0.5D);
|
||||
}
|
||||
|
||||
public boolean hasChest()
|
||||
{
|
||||
return ((Boolean)this.dataManager.get(DATA_ID_CHEST)).booleanValue();
|
||||
}
|
||||
|
||||
public void setChested(boolean chested)
|
||||
{
|
||||
this.dataManager.set(DATA_ID_CHEST, Boolean.valueOf(chested));
|
||||
}
|
||||
|
||||
protected int getInventorySize()
|
||||
{
|
||||
return this.hasChest() ? 17 : super.getInventorySize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y offset from the entity's position for any entity riding this one.
|
||||
*/
|
||||
public double getMountedYOffset()
|
||||
{
|
||||
return super.getMountedYOffset() - 0.25D;
|
||||
}
|
||||
|
||||
protected SoundEvent getAngrySound()
|
||||
{
|
||||
super.getAngrySound();
|
||||
return SoundEvents.ENTITY_DONKEY_ANGRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mob's health reaches 0.
|
||||
*/
|
||||
public void onDeath(DamageSource cause)
|
||||
{
|
||||
super.onDeath(cause);
|
||||
|
||||
if (this.hasChest())
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.dropItem(Item.getItemFromBlock(Blocks.CHEST), 1);
|
||||
}
|
||||
|
||||
this.setChested(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerFixesAbstractChestHorse(DataFixer fixer, Class<?> entityClass)
|
||||
{
|
||||
AbstractHorse.registerFixesAbstractHorse(fixer, entityClass);
|
||||
fixer.registerWalker(FixTypes.ENTITY, new ItemStackDataLists(entityClass, new String[] {"Items"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("ChestedHorse", this.hasChest());
|
||||
|
||||
if (this.hasChest())
|
||||
{
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
for (int i = 2; i < this.horseChest.getSizeInventory(); ++i)
|
||||
{
|
||||
ItemStack itemstack = this.horseChest.getStackInSlot(i);
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
nbttagcompound.setByte("Slot", (byte)i);
|
||||
itemstack.writeToNBT(nbttagcompound);
|
||||
nbttaglist.appendTag(nbttagcompound);
|
||||
}
|
||||
}
|
||||
|
||||
compound.setTag("Items", nbttaglist);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setChested(compound.getBoolean("ChestedHorse"));
|
||||
|
||||
if (this.hasChest())
|
||||
{
|
||||
NBTTagList nbttaglist = compound.getTagList("Items", 10);
|
||||
this.initHorseChest();
|
||||
|
||||
for (int i = 0; i < nbttaglist.tagCount(); ++i)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i);
|
||||
int j = nbttagcompound.getByte("Slot") & 255;
|
||||
|
||||
if (j >= 2 && j < this.horseChest.getSizeInventory())
|
||||
{
|
||||
this.horseChest.setInventorySlotContents(j, new ItemStack(nbttagcompound));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateHorseSlots();
|
||||
}
|
||||
|
||||
public boolean replaceItemInInventory(int inventorySlot, ItemStack itemStackIn)
|
||||
{
|
||||
if (inventorySlot == 499)
|
||||
{
|
||||
if (this.hasChest() && itemStackIn.isEmpty())
|
||||
{
|
||||
this.setChested(false);
|
||||
this.initHorseChest();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.hasChest() && itemStackIn.getItem() == Item.getItemFromBlock(Blocks.CHEST))
|
||||
{
|
||||
this.setChested(true);
|
||||
this.initHorseChest();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.replaceItemInInventory(inventorySlot, itemStackIn);
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (itemstack.getItem() == Items.SPAWN_EGG)
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.isChild())
|
||||
{
|
||||
if (this.isTame() && player.isSneaking())
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.isBeingRidden())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
boolean flag = this.handleEating(player, itemstack);
|
||||
|
||||
if (!flag && !this.isTame())
|
||||
{
|
||||
if (itemstack.interactWithEntity(player, this, hand))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
this.makeMad();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!flag && !this.hasChest() && itemstack.getItem() == Item.getItemFromBlock(Blocks.CHEST))
|
||||
{
|
||||
this.setChested(true);
|
||||
this.playChestEquipSound();
|
||||
flag = true;
|
||||
this.initHorseChest();
|
||||
}
|
||||
|
||||
if (!flag && !this.isChild() && !this.isHorseSaddled() && itemstack.getItem() == Items.SADDLE)
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isChild())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else if (itemstack.interactWithEntity(player, this, hand))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.mountTo(player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void playChestEquipSound()
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_DONKEY_CHEST, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
}
|
||||
|
||||
public int getInventoryColumns()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityAmbientCreature extends EntityLiving implements IAnimals
|
||||
{
|
||||
public EntityAmbientCreature(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public boolean canBeLeashedTo(EntityPlayer player)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class EntityAnimal extends EntityAgeable implements IAnimals
|
||||
{
|
||||
protected Block spawnableBlock = Blocks.GRASS;
|
||||
private int inLove;
|
||||
private UUID playerInLove;
|
||||
|
||||
public EntityAnimal(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
protected void updateAITasks()
|
||||
{
|
||||
if (this.getGrowingAge() != 0)
|
||||
{
|
||||
this.inLove = 0;
|
||||
}
|
||||
|
||||
super.updateAITasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
|
||||
if (this.getGrowingAge() != 0)
|
||||
{
|
||||
this.inLove = 0;
|
||||
}
|
||||
|
||||
if (this.inLove > 0)
|
||||
{
|
||||
--this.inLove;
|
||||
|
||||
if (this.inLove % 10 == 0)
|
||||
{
|
||||
double d0 = this.rand.nextGaussian() * 0.02D;
|
||||
double d1 = this.rand.nextGaussian() * 0.02D;
|
||||
double d2 = this.rand.nextGaussian() * 0.02D;
|
||||
this.world.spawnParticle(EnumParticleTypes.HEART, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, d0, d1, d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.inLove = 0;
|
||||
return super.attackEntityFrom(source, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public float getBlockPathWeight(BlockPos pos)
|
||||
{
|
||||
return this.world.getBlockState(pos.down()).getBlock() == this.spawnableBlock ? 10.0F : this.world.getLightBrightness(pos) - 0.5F;
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("InLove", this.inLove);
|
||||
|
||||
if (this.playerInLove != null)
|
||||
{
|
||||
compound.setUniqueId("LoveCause", this.playerInLove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y Offset of this entity.
|
||||
*/
|
||||
public double getYOffset()
|
||||
{
|
||||
return 0.14D;
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.inLove = compound.getInteger("InLove");
|
||||
this.playerInLove = compound.hasUniqueId("LoveCause") ? compound.getUniqueId("LoveCause") : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
int i = MathHelper.floor(this.posX);
|
||||
int j = MathHelper.floor(this.getEntityBoundingBox().minY);
|
||||
int k = MathHelper.floor(this.posZ);
|
||||
BlockPos blockpos = new BlockPos(i, j, k);
|
||||
return this.world.getBlockState(blockpos.down()).getBlock() == this.spawnableBlock && this.world.getLight(blockpos) > 8 && super.getCanSpawnHere();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks, at least during which the living entity will be silent.
|
||||
*/
|
||||
public int getTalkInterval()
|
||||
{
|
||||
return 120;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an entity can be despawned, used on idle far away entities
|
||||
*/
|
||||
protected boolean canDespawn()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the experience points the entity currently has.
|
||||
*/
|
||||
protected int getExperiencePoints(EntityPlayer player)
|
||||
{
|
||||
return 1 + this.world.rand.nextInt(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return stack.getItem() == Items.WHEAT;
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
if (this.isBreedingItem(itemstack) && this.getGrowingAge() == 0 && this.inLove <= 0)
|
||||
{
|
||||
this.consumeItemFromStack(player, itemstack);
|
||||
this.setInLove(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.isChild() && this.isBreedingItem(itemstack))
|
||||
{
|
||||
this.consumeItemFromStack(player, itemstack);
|
||||
this.ageUp((int)((float)(-this.getGrowingAge() / 20) * 0.1F), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases ItemStack size by one
|
||||
*/
|
||||
protected void consumeItemFromStack(EntityPlayer player, ItemStack stack)
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
stack.shrink(1);
|
||||
}
|
||||
}
|
||||
|
||||
public void setInLove(@Nullable EntityPlayer player)
|
||||
{
|
||||
this.inLove = 600;
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
this.playerInLove = player.getUniqueID();
|
||||
}
|
||||
|
||||
this.world.setEntityState(this, (byte)18);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityPlayerMP getLoveCause()
|
||||
{
|
||||
if (this.playerInLove == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityPlayer entityplayer = this.world.getPlayerEntityByUUID(this.playerInLove);
|
||||
return entityplayer instanceof EntityPlayerMP ? (EntityPlayerMP)entityplayer : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the entity is currently in 'love mode'.
|
||||
*/
|
||||
public boolean isInLove()
|
||||
{
|
||||
return this.inLove > 0;
|
||||
}
|
||||
|
||||
public void resetInLove()
|
||||
{
|
||||
this.inLove = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
if (otherAnimal == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (otherAnimal.getClass() != this.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.isInLove() && otherAnimal.isInLove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 18)
|
||||
{
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
double d0 = this.rand.nextGaussian() * 0.02D;
|
||||
double d1 = this.rand.nextGaussian() * 0.02D;
|
||||
double d2 = this.rand.nextGaussian() * 0.02D;
|
||||
this.world.spawnParticle(EnumParticleTypes.HEART, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, d0, d1, d2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import java.util.Calendar;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
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.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityBat extends EntityAmbientCreature
|
||||
{
|
||||
private static final DataParameter<Byte> HANGING = EntityDataManager.<Byte>createKey(EntityBat.class, DataSerializers.BYTE);
|
||||
/** Coordinates of where the bat spawned. */
|
||||
private BlockPos spawnPosition;
|
||||
|
||||
public EntityBat(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.5F, 0.9F);
|
||||
this.setIsBatHanging(true);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(HANGING, Byte.valueOf((byte)0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume for the sounds this mob makes.
|
||||
*/
|
||||
protected float getSoundVolume()
|
||||
{
|
||||
return 0.1F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pitch of living sounds in living entities.
|
||||
*/
|
||||
protected float getSoundPitch()
|
||||
{
|
||||
return super.getSoundPitch() * 0.95F;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SoundEvent getAmbientSound()
|
||||
{
|
||||
return this.getIsBatHanging() && this.rand.nextInt(4) != 0 ? null : SoundEvents.ENTITY_BAT_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_BAT_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_BAT_DEATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this entity should push and be pushed by other entities when colliding.
|
||||
*/
|
||||
public boolean canBePushed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void collideWithEntity(Entity entityIn)
|
||||
{
|
||||
}
|
||||
|
||||
protected void collideWithNearbyEntities()
|
||||
{
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(6.0D);
|
||||
}
|
||||
|
||||
public boolean getIsBatHanging()
|
||||
{
|
||||
return (((Byte)this.dataManager.get(HANGING)).byteValue() & 1) != 0;
|
||||
}
|
||||
|
||||
public void setIsBatHanging(boolean isHanging)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(HANGING)).byteValue();
|
||||
|
||||
if (isHanging)
|
||||
{
|
||||
this.dataManager.set(HANGING, Byte.valueOf((byte)(b0 | 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(HANGING, Byte.valueOf((byte)(b0 & -2)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
super.onUpdate();
|
||||
|
||||
if (this.getIsBatHanging())
|
||||
{
|
||||
this.motionX = 0.0D;
|
||||
this.motionY = 0.0D;
|
||||
this.motionZ = 0.0D;
|
||||
this.posY = (double)MathHelper.floor(this.posY) + 1.0D - (double)this.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.motionY *= 0.6000000238418579D;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateAITasks()
|
||||
{
|
||||
super.updateAITasks();
|
||||
BlockPos blockpos = new BlockPos(this);
|
||||
BlockPos blockpos1 = blockpos.up();
|
||||
|
||||
if (this.getIsBatHanging())
|
||||
{
|
||||
if (this.world.getBlockState(blockpos1).isNormalCube())
|
||||
{
|
||||
if (this.rand.nextInt(200) == 0)
|
||||
{
|
||||
this.rotationYawHead = (float)this.rand.nextInt(360);
|
||||
}
|
||||
|
||||
if (this.world.getNearestPlayerNotCreative(this, 4.0D) != null)
|
||||
{
|
||||
this.setIsBatHanging(false);
|
||||
this.world.playEvent((EntityPlayer)null, 1025, blockpos, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setIsBatHanging(false);
|
||||
this.world.playEvent((EntityPlayer)null, 1025, blockpos, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.spawnPosition != null && (!this.world.isAirBlock(this.spawnPosition) || this.spawnPosition.getY() < 1))
|
||||
{
|
||||
this.spawnPosition = null;
|
||||
}
|
||||
|
||||
if (this.spawnPosition == null || this.rand.nextInt(30) == 0 || this.spawnPosition.distanceSq((double)((int)this.posX), (double)((int)this.posY), (double)((int)this.posZ)) < 4.0D)
|
||||
{
|
||||
this.spawnPosition = new BlockPos((int)this.posX + this.rand.nextInt(7) - this.rand.nextInt(7), (int)this.posY + this.rand.nextInt(6) - 2, (int)this.posZ + this.rand.nextInt(7) - this.rand.nextInt(7));
|
||||
}
|
||||
|
||||
double d0 = (double)this.spawnPosition.getX() + 0.5D - this.posX;
|
||||
double d1 = (double)this.spawnPosition.getY() + 0.1D - this.posY;
|
||||
double d2 = (double)this.spawnPosition.getZ() + 0.5D - this.posZ;
|
||||
this.motionX += (Math.signum(d0) * 0.5D - this.motionX) * 0.10000000149011612D;
|
||||
this.motionY += (Math.signum(d1) * 0.699999988079071D - this.motionY) * 0.10000000149011612D;
|
||||
this.motionZ += (Math.signum(d2) * 0.5D - this.motionZ) * 0.10000000149011612D;
|
||||
float f = (float)(MathHelper.atan2(this.motionZ, this.motionX) * (180D / Math.PI)) - 90.0F;
|
||||
float f1 = MathHelper.wrapDegrees(f - this.rotationYaw);
|
||||
this.moveForward = 0.5F;
|
||||
this.rotationYaw += f1;
|
||||
|
||||
if (this.rand.nextInt(100) == 0 && this.world.getBlockState(blockpos1).isNormalCube())
|
||||
{
|
||||
this.setIsBatHanging(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
|
||||
* prevent them from trampling crops
|
||||
*/
|
||||
protected boolean canTriggerWalking()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this entity should NOT trigger a pressure plate or a tripwire.
|
||||
*/
|
||||
public boolean doesEntityNotTriggerPressurePlate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.world.isRemote && this.getIsBatHanging())
|
||||
{
|
||||
this.setIsBatHanging(false);
|
||||
}
|
||||
|
||||
return super.attackEntityFrom(source, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerFixesBat(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityBat.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.dataManager.set(HANGING, Byte.valueOf(compound.getByte("BatFlags")));
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setByte("BatFlags", ((Byte)this.dataManager.get(HANGING)).byteValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ);
|
||||
|
||||
if (blockpos.getY() >= this.world.getSeaLevel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = this.world.getLightFromNeighbors(blockpos);
|
||||
int j = 4;
|
||||
|
||||
if (this.isDateAroundHalloween(this.world.getCurrentDate()))
|
||||
{
|
||||
j = 7;
|
||||
}
|
||||
else if (this.rand.nextBoolean())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return i > this.rand.nextInt(j) ? false : super.getCanSpawnHere();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDateAroundHalloween(Calendar p_175569_1_)
|
||||
{
|
||||
return p_175569_1_.get(2) + 1 == 10 && p_175569_1_.get(5) >= 20 || p_175569_1_.get(2) + 1 == 11 && p_175569_1_.get(5) <= 3;
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.height / 2.0F;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_BAT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIFollowParent;
|
||||
import net.minecraft.entity.ai.EntityAILookIdle;
|
||||
import net.minecraft.entity.ai.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
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.pathfinding.PathNodeType;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityChicken extends EntityAnimal
|
||||
{
|
||||
private static final Set<Item> TEMPTATION_ITEMS = Sets.newHashSet(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
|
||||
public float wingRotation;
|
||||
public float destPos;
|
||||
public float oFlapSpeed;
|
||||
public float oFlap;
|
||||
public float wingRotDelta = 1.0F;
|
||||
/** The time until the next egg is spawned. */
|
||||
public int timeUntilNextEgg;
|
||||
public boolean chickenJockey;
|
||||
|
||||
public EntityChicken(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.4F, 0.7F);
|
||||
this.timeUntilNextEgg = this.rand.nextInt(6000) + 6000;
|
||||
this.setPathPriority(PathNodeType.WATER, 0.0F);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIPanic(this, 1.4D));
|
||||
this.tasks.addTask(2, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.0D, false, TEMPTATION_ITEMS));
|
||||
this.tasks.addTask(4, new EntityAIFollowParent(this, 1.1D));
|
||||
this.tasks.addTask(5, new EntityAIWanderAvoidWater(this, 1.0D));
|
||||
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(7, new EntityAILookIdle(this));
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.height;
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(4.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25D);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
this.oFlap = this.wingRotation;
|
||||
this.oFlapSpeed = this.destPos;
|
||||
this.destPos = (float)((double)this.destPos + (double)(this.onGround ? -1 : 4) * 0.3D);
|
||||
this.destPos = MathHelper.clamp(this.destPos, 0.0F, 1.0F);
|
||||
|
||||
if (!this.onGround && this.wingRotDelta < 1.0F)
|
||||
{
|
||||
this.wingRotDelta = 1.0F;
|
||||
}
|
||||
|
||||
this.wingRotDelta = (float)((double)this.wingRotDelta * 0.9D);
|
||||
|
||||
if (!this.onGround && this.motionY < 0.0D)
|
||||
{
|
||||
this.motionY *= 0.6D;
|
||||
}
|
||||
|
||||
this.wingRotation += this.wingRotDelta * 2.0F;
|
||||
|
||||
if (!this.world.isRemote && !this.isChild() && !this.isChickenJockey() && --this.timeUntilNextEgg <= 0)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_CHICKEN_EGG, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
this.dropItem(Items.EGG, 1);
|
||||
this.timeUntilNextEgg = this.rand.nextInt(6000) + 6000;
|
||||
}
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_CHICKEN_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_CHICKEN_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_CHICKEN_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_CHICKEN_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_CHICKEN;
|
||||
}
|
||||
|
||||
public EntityChicken createChild(EntityAgeable ageable)
|
||||
{
|
||||
return new EntityChicken(this.world);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return TEMPTATION_ITEMS.contains(stack.getItem());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the experience points the entity currently has.
|
||||
*/
|
||||
protected int getExperiencePoints(EntityPlayer player)
|
||||
{
|
||||
return this.isChickenJockey() ? 10 : super.getExperiencePoints(player);
|
||||
}
|
||||
|
||||
public static void registerFixesChicken(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityChicken.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.chickenJockey = compound.getBoolean("IsChickenJockey");
|
||||
|
||||
if (compound.hasKey("EggLayTime"))
|
||||
{
|
||||
this.timeUntilNextEgg = compound.getInteger("EggLayTime");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("IsChickenJockey", this.chickenJockey);
|
||||
compound.setInteger("EggLayTime", this.timeUntilNextEgg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an entity can be despawned, used on idle far away entities
|
||||
*/
|
||||
protected boolean canDespawn()
|
||||
{
|
||||
return this.isChickenJockey() && !this.isBeingRidden();
|
||||
}
|
||||
|
||||
public void updatePassenger(Entity passenger)
|
||||
{
|
||||
super.updatePassenger(passenger);
|
||||
float f = MathHelper.sin(this.renderYawOffset * 0.017453292F);
|
||||
float f1 = MathHelper.cos(this.renderYawOffset * 0.017453292F);
|
||||
float f2 = 0.1F;
|
||||
float f3 = 0.0F;
|
||||
passenger.setPosition(this.posX + (double)(0.1F * f), this.posY + (double)(this.height * 0.5F) + passenger.getYOffset() + 0.0D, this.posZ - (double)(0.1F * f1));
|
||||
|
||||
if (passenger instanceof EntityLivingBase)
|
||||
{
|
||||
((EntityLivingBase)passenger).renderYawOffset = this.renderYawOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this chicken is a jokey with a zombie riding it.
|
||||
*/
|
||||
public boolean isChickenJockey()
|
||||
{
|
||||
return this.chickenJockey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this chicken is a jockey or not.
|
||||
*/
|
||||
public void setChickenJockey(boolean jockey)
|
||||
{
|
||||
this.chickenJockey = jockey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIFollowParent;
|
||||
import net.minecraft.entity.ai.EntityAILookIdle;
|
||||
import net.minecraft.entity.ai.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityCow extends EntityAnimal
|
||||
{
|
||||
public EntityCow(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.9F, 1.4F);
|
||||
}
|
||||
|
||||
public static void registerFixesCow(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityCow.class);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIPanic(this, 2.0D));
|
||||
this.tasks.addTask(2, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.25D, Items.WHEAT, false));
|
||||
this.tasks.addTask(4, new EntityAIFollowParent(this, 1.25D));
|
||||
this.tasks.addTask(5, new EntityAIWanderAvoidWater(this, 1.0D));
|
||||
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(7, new EntityAILookIdle(this));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_COW_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_COW_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_COW_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_COW_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume for the sounds this mob makes.
|
||||
*/
|
||||
protected float getSoundVolume()
|
||||
{
|
||||
return 0.4F;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_COW;
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (itemstack.getItem() == Items.BUCKET && !player.capabilities.isCreativeMode && !this.isChild())
|
||||
{
|
||||
player.playSound(SoundEvents.ENTITY_COW_MILK, 1.0F, 1.0F);
|
||||
itemstack.shrink(1);
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
player.setHeldItem(hand, new ItemStack(Items.MILK_BUCKET));
|
||||
}
|
||||
else if (!player.inventory.addItemStackToInventory(new ItemStack(Items.MILK_BUCKET)))
|
||||
{
|
||||
player.dropItem(new ItemStack(Items.MILK_BUCKET), false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
public EntityCow createChild(EntityAgeable ageable)
|
||||
{
|
||||
return new EntityCow(this.world);
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.isChild() ? this.height : 1.3F;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityDonkey extends AbstractChestHorse
|
||||
{
|
||||
public EntityDonkey(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public static void registerFixesDonkey(DataFixer fixer)
|
||||
{
|
||||
AbstractChestHorse.registerFixesAbstractChestHorse(fixer, EntityDonkey.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_DONKEY;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
super.getAmbientSound();
|
||||
return SoundEvents.ENTITY_DONKEY_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
super.getDeathSound();
|
||||
return SoundEvents.ENTITY_DONKEY_DEATH;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
super.getHurtSound(damageSourceIn);
|
||||
return SoundEvents.ENTITY_DONKEY_HURT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
if (otherAnimal == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!(otherAnimal instanceof EntityDonkey) && !(otherAnimal instanceof EntityHorse))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.canMate() && ((AbstractHorse)otherAnimal).canMate();
|
||||
}
|
||||
}
|
||||
|
||||
public EntityAgeable createChild(EntityAgeable ageable)
|
||||
{
|
||||
AbstractHorse abstracthorse = (AbstractHorse)(ageable instanceof EntityHorse ? new EntityMule(this.world) : new EntityDonkey(this.world));
|
||||
this.setOffspringAttributes(ageable, abstracthorse);
|
||||
return abstracthorse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
public interface EntityFlying
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
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.util.datafix.DataFixer;
|
||||
import net.minecraft.util.datafix.FixTypes;
|
||||
import net.minecraft.util.datafix.walkers.ItemStackData;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityHorse extends AbstractHorse
|
||||
{
|
||||
private static final UUID ARMOR_MODIFIER_UUID = UUID.fromString("556E1665-8B10-40C8-8F9D-CF9B1667F295");
|
||||
private static final DataParameter<Integer> HORSE_VARIANT = EntityDataManager.<Integer>createKey(EntityHorse.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Integer> HORSE_ARMOR = EntityDataManager.<Integer>createKey(EntityHorse.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<ItemStack> HORSE_ARMOR_STACK = EntityDataManager.<ItemStack>createKey(EntityHorse.class, DataSerializers.ITEM_STACK);
|
||||
private static final String[] HORSE_TEXTURES = new String[] {"textures/entity/horse/horse_white.png", "textures/entity/horse/horse_creamy.png", "textures/entity/horse/horse_chestnut.png", "textures/entity/horse/horse_brown.png", "textures/entity/horse/horse_black.png", "textures/entity/horse/horse_gray.png", "textures/entity/horse/horse_darkbrown.png"};
|
||||
private static final String[] HORSE_TEXTURES_ABBR = new String[] {"hwh", "hcr", "hch", "hbr", "hbl", "hgr", "hdb"};
|
||||
private static final String[] HORSE_MARKING_TEXTURES = new String[] {null, "textures/entity/horse/horse_markings_white.png", "textures/entity/horse/horse_markings_whitefield.png", "textures/entity/horse/horse_markings_whitedots.png", "textures/entity/horse/horse_markings_blackdots.png"};
|
||||
private static final String[] HORSE_MARKING_TEXTURES_ABBR = new String[] {"", "wo_", "wmo", "wdo", "bdo"};
|
||||
private String texturePrefix;
|
||||
private final String[] horseTexturesArray = new String[3];
|
||||
|
||||
public EntityHorse(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(HORSE_VARIANT, Integer.valueOf(0));
|
||||
this.dataManager.register(HORSE_ARMOR, Integer.valueOf(HorseArmorType.NONE.getOrdinal()));
|
||||
this.dataManager.register(HORSE_ARMOR_STACK, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
public static void registerFixesHorse(DataFixer fixer)
|
||||
{
|
||||
AbstractHorse.registerFixesAbstractHorse(fixer, EntityHorse.class);
|
||||
fixer.registerWalker(FixTypes.ENTITY, new ItemStackData(EntityHorse.class, new String[] {"ArmorItem"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("Variant", this.getHorseVariant());
|
||||
|
||||
if (!this.horseChest.getStackInSlot(1).isEmpty())
|
||||
{
|
||||
compound.setTag("ArmorItem", this.horseChest.getStackInSlot(1).writeToNBT(new NBTTagCompound()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setHorseVariant(compound.getInteger("Variant"));
|
||||
|
||||
if (compound.hasKey("ArmorItem", 10))
|
||||
{
|
||||
ItemStack itemstack = new ItemStack(compound.getCompoundTag("ArmorItem"));
|
||||
|
||||
if (!itemstack.isEmpty() && isArmor(itemstack))
|
||||
{
|
||||
this.horseChest.setInventorySlotContents(1, itemstack);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateHorseSlots();
|
||||
}
|
||||
|
||||
public void setHorseVariant(int variant)
|
||||
{
|
||||
this.dataManager.set(HORSE_VARIANT, Integer.valueOf(variant));
|
||||
this.resetTexturePrefix();
|
||||
}
|
||||
|
||||
public int getHorseVariant()
|
||||
{
|
||||
return ((Integer)this.dataManager.get(HORSE_VARIANT)).intValue();
|
||||
}
|
||||
|
||||
private void resetTexturePrefix()
|
||||
{
|
||||
this.texturePrefix = null;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private void setHorseTexturePaths()
|
||||
{
|
||||
int i = this.getHorseVariant();
|
||||
int j = (i & 255) % 7;
|
||||
int k = ((i & 65280) >> 8) % 5;
|
||||
ItemStack armorStack = this.dataManager.get(HORSE_ARMOR_STACK);
|
||||
String texture = !armorStack.isEmpty() ? armorStack.getItem().getHorseArmorTexture(this, armorStack) : HorseArmorType.getByOrdinal(this.dataManager.get(HORSE_ARMOR)).getTextureName(); //If armorStack is empty, the server is vanilla so the texture should be determined the vanilla way
|
||||
this.horseTexturesArray[0] = HORSE_TEXTURES[j];
|
||||
this.horseTexturesArray[1] = HORSE_MARKING_TEXTURES[k];
|
||||
this.horseTexturesArray[2] = texture;
|
||||
this.texturePrefix = "horse/" + HORSE_TEXTURES_ABBR[j] + HORSE_MARKING_TEXTURES_ABBR[k] + texture;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getHorseTexture()
|
||||
{
|
||||
if (this.texturePrefix == null)
|
||||
{
|
||||
this.setHorseTexturePaths();
|
||||
}
|
||||
|
||||
return this.texturePrefix;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String[] getVariantTexturePaths()
|
||||
{
|
||||
if (this.texturePrefix == null)
|
||||
{
|
||||
this.setHorseTexturePaths();
|
||||
}
|
||||
|
||||
return this.horseTexturesArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the items in the saddle and armor slots of the horse's inventory.
|
||||
*/
|
||||
protected void updateHorseSlots()
|
||||
{
|
||||
super.updateHorseSlots();
|
||||
this.setHorseArmorStack(this.horseChest.getStackInSlot(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set horse armor stack (for example: new ItemStack(Items.iron_horse_armor))
|
||||
*/
|
||||
public void setHorseArmorStack(ItemStack itemStackIn)
|
||||
{
|
||||
HorseArmorType horsearmortype = HorseArmorType.getByItemStack(itemStackIn);
|
||||
this.dataManager.set(HORSE_ARMOR, Integer.valueOf(horsearmortype.getOrdinal()));
|
||||
this.dataManager.set(HORSE_ARMOR_STACK, itemStackIn);
|
||||
this.resetTexturePrefix();
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.ARMOR).removeModifier(ARMOR_MODIFIER_UUID);
|
||||
int i = horsearmortype.getProtection();
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.ARMOR).applyModifier((new AttributeModifier(ARMOR_MODIFIER_UUID, "Horse armor bonus", (double)i, 0)).setSaved(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HorseArmorType getHorseArmorType()
|
||||
{
|
||||
HorseArmorType armor = HorseArmorType.getByItemStack(this.dataManager.get(HORSE_ARMOR_STACK)); //First check the Forge armor DataParameter
|
||||
if (armor == HorseArmorType.NONE) armor = HorseArmorType.getByOrdinal(this.dataManager.get(HORSE_ARMOR)); //If the Forge armor DataParameter returns NONE, fallback to the vanilla armor DataParameter. This is necessary to prevent issues with Forge clients connected to vanilla servers.
|
||||
return armor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by InventoryBasic.onInventoryChanged() on a array that is never filled.
|
||||
*/
|
||||
public void onInventoryChanged(IInventory invBasic)
|
||||
{
|
||||
HorseArmorType horsearmortype = this.getHorseArmorType();
|
||||
super.onInventoryChanged(invBasic);
|
||||
HorseArmorType horsearmortype1 = this.getHorseArmorType();
|
||||
|
||||
if (this.ticksExisted > 20 && horsearmortype != horsearmortype1 && horsearmortype1 != HorseArmorType.NONE)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_HORSE_ARMOR, 0.5F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playGallopSound(SoundType p_190680_1_)
|
||||
{
|
||||
super.playGallopSound(p_190680_1_);
|
||||
|
||||
if (this.rand.nextInt(10) == 0)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_HORSE_BREATHE, p_190680_1_.getVolume() * 0.6F, p_190680_1_.getPitch());
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue((double)this.getModifiedMaxHealth());
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(this.getModifiedMovementSpeed());
|
||||
this.getEntityAttribute(JUMP_STRENGTH).setBaseValue(this.getModifiedJumpStrength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
super.onUpdate();
|
||||
|
||||
if (this.world.isRemote && this.dataManager.isDirty())
|
||||
{
|
||||
this.dataManager.setClean();
|
||||
this.resetTexturePrefix();
|
||||
}
|
||||
ItemStack armor = this.horseChest.getStackInSlot(1);
|
||||
if (isArmor(armor)) armor.getItem().onHorseArmorTick(world, this, armor);
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
super.getAmbientSound();
|
||||
return SoundEvents.ENTITY_HORSE_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
super.getDeathSound();
|
||||
return SoundEvents.ENTITY_HORSE_DEATH;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
super.getHurtSound(damageSourceIn);
|
||||
return SoundEvents.ENTITY_HORSE_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getAngrySound()
|
||||
{
|
||||
super.getAngrySound();
|
||||
return SoundEvents.ENTITY_HORSE_ANGRY;
|
||||
}
|
||||
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_HORSE;
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
boolean flag = !itemstack.isEmpty();
|
||||
|
||||
if (flag && itemstack.getItem() == Items.SPAWN_EGG)
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.isChild())
|
||||
{
|
||||
if (this.isTame() && player.isSneaking())
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.isBeingRidden())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (this.handleEating(player, itemstack))
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemstack.interactWithEntity(player, this, hand))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.isTame())
|
||||
{
|
||||
this.makeMad();
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean flag1 = HorseArmorType.getByItemStack(itemstack) != HorseArmorType.NONE;
|
||||
boolean flag2 = !this.isChild() && !this.isHorseSaddled() && itemstack.getItem() == Items.SADDLE;
|
||||
|
||||
if (flag1 || flag2)
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isChild())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.mountTo(player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
if (otherAnimal == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!(otherAnimal instanceof EntityDonkey) && !(otherAnimal instanceof EntityHorse))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.canMate() && ((AbstractHorse)otherAnimal).canMate();
|
||||
}
|
||||
}
|
||||
|
||||
public EntityAgeable createChild(EntityAgeable ageable)
|
||||
{
|
||||
AbstractHorse abstracthorse;
|
||||
|
||||
if (ageable instanceof EntityDonkey)
|
||||
{
|
||||
abstracthorse = new EntityMule(this.world);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityHorse entityhorse = (EntityHorse)ageable;
|
||||
abstracthorse = new EntityHorse(this.world);
|
||||
int j = this.rand.nextInt(9);
|
||||
int i;
|
||||
|
||||
if (j < 4)
|
||||
{
|
||||
i = this.getHorseVariant() & 255;
|
||||
}
|
||||
else if (j < 8)
|
||||
{
|
||||
i = entityhorse.getHorseVariant() & 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = this.rand.nextInt(7);
|
||||
}
|
||||
|
||||
int k = this.rand.nextInt(5);
|
||||
|
||||
if (k < 2)
|
||||
{
|
||||
i = i | this.getHorseVariant() & 65280;
|
||||
}
|
||||
else if (k < 4)
|
||||
{
|
||||
i = i | entityhorse.getHorseVariant() & 65280;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = i | this.rand.nextInt(5) << 8 & 65280;
|
||||
}
|
||||
|
||||
((EntityHorse)abstracthorse).setHorseVariant(i);
|
||||
}
|
||||
|
||||
this.setOffspringAttributes(ageable, abstracthorse);
|
||||
return abstracthorse;
|
||||
}
|
||||
|
||||
public boolean wearsArmor()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isArmor(ItemStack stack)
|
||||
{
|
||||
return HorseArmorType.isHorseArmor(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
livingdata = super.onInitialSpawn(difficulty, livingdata);
|
||||
int i;
|
||||
|
||||
if (livingdata instanceof EntityHorse.GroupData)
|
||||
{
|
||||
i = ((EntityHorse.GroupData)livingdata).variant;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = this.rand.nextInt(7);
|
||||
livingdata = new EntityHorse.GroupData(i);
|
||||
}
|
||||
|
||||
this.setHorseVariant(i | this.rand.nextInt(5) << 8);
|
||||
return livingdata;
|
||||
}
|
||||
|
||||
public static class GroupData implements IEntityLivingData
|
||||
{
|
||||
public int variant;
|
||||
|
||||
public GroupData(int variantIn)
|
||||
{
|
||||
this.variant = variantIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,614 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.IRangedAttackMob;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIAttackRanged;
|
||||
import net.minecraft.entity.ai.EntityAIFollowParent;
|
||||
import net.minecraft.entity.ai.EntityAIHurtByTarget;
|
||||
import net.minecraft.entity.ai.EntityAILlamaFollowCaravan;
|
||||
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.EntityAIRunAroundLikeCrazy;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.projectile.EntityLlamaSpit;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
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.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityLlama extends AbstractChestHorse implements IRangedAttackMob
|
||||
{
|
||||
private static final DataParameter<Integer> DATA_STRENGTH_ID = EntityDataManager.<Integer>createKey(EntityLlama.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Integer> DATA_COLOR_ID = EntityDataManager.<Integer>createKey(EntityLlama.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Integer> DATA_VARIANT_ID = EntityDataManager.<Integer>createKey(EntityLlama.class, DataSerializers.VARINT);
|
||||
private boolean didSpit;
|
||||
@Nullable
|
||||
private EntityLlama caravanHead;
|
||||
@Nullable
|
||||
private EntityLlama caravanTail;
|
||||
|
||||
public EntityLlama(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.9F, 1.87F);
|
||||
}
|
||||
|
||||
private void setStrength(int strengthIn)
|
||||
{
|
||||
this.dataManager.set(DATA_STRENGTH_ID, Integer.valueOf(Math.max(1, Math.min(5, strengthIn))));
|
||||
}
|
||||
|
||||
private void setRandomStrength()
|
||||
{
|
||||
int i = this.rand.nextFloat() < 0.04F ? 5 : 3;
|
||||
this.setStrength(1 + this.rand.nextInt(i));
|
||||
}
|
||||
|
||||
public int getStrength()
|
||||
{
|
||||
return ((Integer)this.dataManager.get(DATA_STRENGTH_ID)).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("Variant", this.getVariant());
|
||||
compound.setInteger("Strength", this.getStrength());
|
||||
|
||||
if (!this.horseChest.getStackInSlot(1).isEmpty())
|
||||
{
|
||||
compound.setTag("DecorItem", this.horseChest.getStackInSlot(1).writeToNBT(new NBTTagCompound()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
this.setStrength(compound.getInteger("Strength"));
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setVariant(compound.getInteger("Variant"));
|
||||
|
||||
if (compound.hasKey("DecorItem", 10))
|
||||
{
|
||||
this.horseChest.setInventorySlotContents(1, new ItemStack(compound.getCompoundTag("DecorItem")));
|
||||
}
|
||||
|
||||
this.updateHorseSlots();
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIRunAroundLikeCrazy(this, 1.2D));
|
||||
this.tasks.addTask(2, new EntityAILlamaFollowCaravan(this, 2.0999999046325684D));
|
||||
this.tasks.addTask(3, new EntityAIAttackRanged(this, 1.25D, 40, 20.0F));
|
||||
this.tasks.addTask(3, new EntityAIPanic(this, 1.2D));
|
||||
this.tasks.addTask(4, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(5, new EntityAIFollowParent(this, 1.0D));
|
||||
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 0.7D));
|
||||
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(8, new EntityAILookIdle(this));
|
||||
this.targetTasks.addTask(1, new EntityLlama.AIHurtByTarget(this));
|
||||
this.targetTasks.addTask(2, new EntityLlama.AIDefendTarget(this));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(40.0D);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(DATA_STRENGTH_ID, Integer.valueOf(0));
|
||||
this.dataManager.register(DATA_COLOR_ID, Integer.valueOf(-1));
|
||||
this.dataManager.register(DATA_VARIANT_ID, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public int getVariant()
|
||||
{
|
||||
return MathHelper.clamp(((Integer)this.dataManager.get(DATA_VARIANT_ID)).intValue(), 0, 3);
|
||||
}
|
||||
|
||||
public void setVariant(int variantIn)
|
||||
{
|
||||
this.dataManager.set(DATA_VARIANT_ID, Integer.valueOf(variantIn));
|
||||
}
|
||||
|
||||
protected int getInventorySize()
|
||||
{
|
||||
return this.hasChest() ? 2 + 3 * this.getInventoryColumns() : super.getInventorySize();
|
||||
}
|
||||
|
||||
public void updatePassenger(Entity passenger)
|
||||
{
|
||||
if (this.isPassenger(passenger))
|
||||
{
|
||||
float f = MathHelper.cos(this.renderYawOffset * 0.017453292F);
|
||||
float f1 = MathHelper.sin(this.renderYawOffset * 0.017453292F);
|
||||
float f2 = 0.3F;
|
||||
passenger.setPosition(this.posX + (double)(0.3F * f1), this.posY + this.getMountedYOffset() + passenger.getYOffset(), this.posZ - (double)(0.3F * f));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y offset from the entity's position for any entity riding this one.
|
||||
*/
|
||||
public double getMountedYOffset()
|
||||
{
|
||||
return (double)this.height * 0.67D;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if all the conditions for steering the entity are met. For pigs, this is true if it is being ridden
|
||||
* by a player and the player is holding a carrot-on-a-stick
|
||||
*/
|
||||
public boolean canBeSteered()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean handleEating(EntityPlayer player, ItemStack stack)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
float f = 0.0F;
|
||||
boolean flag = false;
|
||||
Item item = stack.getItem();
|
||||
|
||||
if (item == Items.WHEAT)
|
||||
{
|
||||
i = 10;
|
||||
j = 3;
|
||||
f = 2.0F;
|
||||
}
|
||||
else if (item == Item.getItemFromBlock(Blocks.HAY_BLOCK))
|
||||
{
|
||||
i = 90;
|
||||
j = 6;
|
||||
f = 10.0F;
|
||||
|
||||
if (this.isTame() && this.getGrowingAge() == 0)
|
||||
{
|
||||
flag = true;
|
||||
this.setInLove(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getHealth() < this.getMaxHealth() && f > 0.0F)
|
||||
{
|
||||
this.heal(f);
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (this.isChild() && i > 0)
|
||||
{
|
||||
this.world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, 0.0D, 0.0D, 0.0D);
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.addGrowth(i);
|
||||
}
|
||||
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (j > 0 && (flag || !this.isTame()) && this.getTemper() < this.getMaxTemper())
|
||||
{
|
||||
flag = true;
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.increaseTemper(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (flag && !this.isSilent())
|
||||
{
|
||||
this.world.playSound((EntityPlayer)null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_LLAMA_EAT, this.getSoundCategory(), 1.0F, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dead and sleeping entities cannot move
|
||||
*/
|
||||
protected boolean isMovementBlocked()
|
||||
{
|
||||
return this.getHealth() <= 0.0F || this.isEatingHaystack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
livingdata = super.onInitialSpawn(difficulty, livingdata);
|
||||
this.setRandomStrength();
|
||||
int i;
|
||||
|
||||
if (livingdata instanceof EntityLlama.GroupData)
|
||||
{
|
||||
i = ((EntityLlama.GroupData)livingdata).variant;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = this.rand.nextInt(4);
|
||||
livingdata = new EntityLlama.GroupData(i);
|
||||
}
|
||||
|
||||
this.setVariant(i);
|
||||
return livingdata;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean hasColor()
|
||||
{
|
||||
return this.getColor() != null;
|
||||
}
|
||||
|
||||
protected SoundEvent getAngrySound()
|
||||
{
|
||||
return SoundEvents.ENTITY_LLAMA_ANGRY;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_LLAMA_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_LLAMA_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_LLAMA_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_LLAMA_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
protected void playChestEquipSound()
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_LLAMA_CHEST, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
}
|
||||
|
||||
public void makeMad()
|
||||
{
|
||||
SoundEvent soundevent = this.getAngrySound();
|
||||
|
||||
if (soundevent != null)
|
||||
{
|
||||
this.playSound(soundevent, this.getSoundVolume(), this.getSoundPitch());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_LLAMA;
|
||||
}
|
||||
|
||||
public int getInventoryColumns()
|
||||
{
|
||||
return this.getStrength();
|
||||
}
|
||||
|
||||
public boolean wearsArmor()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isArmor(ItemStack stack)
|
||||
{
|
||||
return stack.getItem() == Item.getItemFromBlock(Blocks.CARPET);
|
||||
}
|
||||
|
||||
public boolean canBeSaddled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by InventoryBasic.onInventoryChanged() on a array that is never filled.
|
||||
*/
|
||||
public void onInventoryChanged(IInventory invBasic)
|
||||
{
|
||||
EnumDyeColor enumdyecolor = this.getColor();
|
||||
super.onInventoryChanged(invBasic);
|
||||
EnumDyeColor enumdyecolor1 = this.getColor();
|
||||
|
||||
if (this.ticksExisted > 20 && enumdyecolor1 != null && enumdyecolor1 != enumdyecolor)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_LLAMA_SWAG, 0.5F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the items in the saddle and armor slots of the horse's inventory.
|
||||
*/
|
||||
protected void updateHorseSlots()
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
super.updateHorseSlots();
|
||||
this.setColorByItem(this.horseChest.getStackInSlot(1));
|
||||
}
|
||||
}
|
||||
|
||||
private void setColor(@Nullable EnumDyeColor color)
|
||||
{
|
||||
this.dataManager.set(DATA_COLOR_ID, Integer.valueOf(color == null ? -1 : color.getMetadata()));
|
||||
}
|
||||
|
||||
private void setColorByItem(ItemStack stack)
|
||||
{
|
||||
if (this.isArmor(stack))
|
||||
{
|
||||
this.setColor(EnumDyeColor.byMetadata(stack.getMetadata()));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setColor((EnumDyeColor)null);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EnumDyeColor getColor()
|
||||
{
|
||||
int i = ((Integer)this.dataManager.get(DATA_COLOR_ID)).intValue();
|
||||
return i == -1 ? null : EnumDyeColor.byMetadata(i);
|
||||
}
|
||||
|
||||
public int getMaxTemper()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
return otherAnimal != this && otherAnimal instanceof EntityLlama && this.canMate() && ((EntityLlama)otherAnimal).canMate();
|
||||
}
|
||||
|
||||
public EntityLlama createChild(EntityAgeable ageable)
|
||||
{
|
||||
EntityLlama entityllama = new EntityLlama(this.world);
|
||||
this.setOffspringAttributes(ageable, entityllama);
|
||||
EntityLlama entityllama1 = (EntityLlama)ageable;
|
||||
int i = this.rand.nextInt(Math.max(this.getStrength(), entityllama1.getStrength())) + 1;
|
||||
|
||||
if (this.rand.nextFloat() < 0.03F)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
entityllama.setStrength(i);
|
||||
entityllama.setVariant(this.rand.nextBoolean() ? this.getVariant() : entityllama1.getVariant());
|
||||
return entityllama;
|
||||
}
|
||||
|
||||
private void spit(EntityLivingBase target)
|
||||
{
|
||||
EntityLlamaSpit entityllamaspit = new EntityLlamaSpit(this.world, this);
|
||||
double d0 = target.posX - this.posX;
|
||||
double d1 = target.getEntityBoundingBox().minY + (double)(target.height / 3.0F) - entityllamaspit.posY;
|
||||
double d2 = target.posZ - this.posZ;
|
||||
float f = MathHelper.sqrt(d0 * d0 + d2 * d2) * 0.2F;
|
||||
entityllamaspit.shoot(d0, d1 + (double)f, d2, 1.5F, 10.0F);
|
||||
this.world.playSound((EntityPlayer)null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_LLAMA_SPIT, this.getSoundCategory(), 1.0F, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
|
||||
this.world.spawnEntity(entityllamaspit);
|
||||
this.didSpit = true;
|
||||
}
|
||||
|
||||
private void setDidSpit(boolean didSpitIn)
|
||||
{
|
||||
this.didSpit = didSpitIn;
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
int i = MathHelper.ceil((distance * 0.5F - 3.0F) * damageMultiplier);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
if (distance >= 6.0F)
|
||||
{
|
||||
this.attackEntityFrom(DamageSource.FALL, (float)i);
|
||||
|
||||
if (this.isBeingRidden())
|
||||
{
|
||||
for (Entity entity : this.getRecursivePassengers())
|
||||
{
|
||||
entity.attackEntityFrom(DamageSource.FALL, (float)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IBlockState iblockstate = this.world.getBlockState(new BlockPos(this.posX, this.posY - 0.2D - (double)this.prevRotationYaw, this.posZ));
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (iblockstate.getMaterial() != Material.AIR && !this.isSilent())
|
||||
{
|
||||
SoundType soundtype = block.getSoundType();
|
||||
this.world.playSound((EntityPlayer)null, this.posX, this.posY, this.posZ, soundtype.getStepSound(), this.getSoundCategory(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void leaveCaravan()
|
||||
{
|
||||
if (this.caravanHead != null)
|
||||
{
|
||||
this.caravanHead.caravanTail = null;
|
||||
}
|
||||
|
||||
this.caravanHead = null;
|
||||
}
|
||||
|
||||
public void joinCaravan(EntityLlama caravanHeadIn)
|
||||
{
|
||||
this.caravanHead = caravanHeadIn;
|
||||
this.caravanHead.caravanTail = this;
|
||||
}
|
||||
|
||||
public boolean hasCaravanTrail()
|
||||
{
|
||||
return this.caravanTail != null;
|
||||
}
|
||||
|
||||
public boolean inCaravan()
|
||||
{
|
||||
return this.caravanHead != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityLlama getCaravanHead()
|
||||
{
|
||||
return this.caravanHead;
|
||||
}
|
||||
|
||||
protected double followLeashSpeed()
|
||||
{
|
||||
return 2.0D;
|
||||
}
|
||||
|
||||
protected void followMother()
|
||||
{
|
||||
if (!this.inCaravan() && this.isChild())
|
||||
{
|
||||
super.followMother();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canEatGrass()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attack the specified entity using a ranged attack.
|
||||
*/
|
||||
public void attackEntityWithRangedAttack(EntityLivingBase target, float distanceFactor)
|
||||
{
|
||||
this.spit(target);
|
||||
}
|
||||
|
||||
public void setSwingingArms(boolean swingingArms)
|
||||
{
|
||||
}
|
||||
|
||||
static class AIDefendTarget extends EntityAINearestAttackableTarget<EntityWolf>
|
||||
{
|
||||
public AIDefendTarget(EntityLlama llama)
|
||||
{
|
||||
super(llama, EntityWolf.class, 16, false, true, (Predicate)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (super.shouldExecute() && this.targetEntity != null && !((EntityWolf)this.targetEntity).isTamed())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.taskOwner.setAttackTarget((EntityLivingBase)null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected double getTargetDistance()
|
||||
{
|
||||
return super.getTargetDistance() * 0.25D;
|
||||
}
|
||||
}
|
||||
|
||||
static class AIHurtByTarget extends EntityAIHurtByTarget
|
||||
{
|
||||
public AIHurtByTarget(EntityLlama llama)
|
||||
{
|
||||
super(llama, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean shouldContinueExecuting()
|
||||
{
|
||||
if (this.taskOwner instanceof EntityLlama)
|
||||
{
|
||||
EntityLlama entityllama = (EntityLlama)this.taskOwner;
|
||||
|
||||
if (entityllama.didSpit)
|
||||
{
|
||||
entityllama.setDidSpit(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return super.shouldContinueExecuting();
|
||||
}
|
||||
}
|
||||
|
||||
static class GroupData implements IEntityLivingData
|
||||
{
|
||||
public int variant;
|
||||
|
||||
private GroupData(int variantIn)
|
||||
{
|
||||
this.variant = variantIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityMooshroom extends EntityCow implements net.minecraftforge.common.IShearable
|
||||
{
|
||||
public EntityMooshroom(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.9F, 1.4F);
|
||||
this.spawnableBlock = Blocks.MYCELIUM;
|
||||
}
|
||||
|
||||
public static void registerFixesMooshroom(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityMooshroom.class);
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (itemstack.getItem() == Items.BOWL && this.getGrowingAge() >= 0 && !player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
player.setHeldItem(hand, new ItemStack(Items.MUSHROOM_STEW));
|
||||
}
|
||||
else if (!player.inventory.addItemStackToInventory(new ItemStack(Items.MUSHROOM_STEW)))
|
||||
{
|
||||
player.dropItem(new ItemStack(Items.MUSHROOM_STEW), false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (false && itemstack.getItem() == Items.SHEARS && this.getGrowingAge() >= 0) //Forge Disable, Moved to onSheared
|
||||
{
|
||||
this.setDead();
|
||||
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY + (double)(this.height / 2.0F), this.posZ, 0.0D, 0.0D, 0.0D);
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
EntityCow entitycow = new EntityCow(this.world);
|
||||
entitycow.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
|
||||
entitycow.setHealth(this.getHealth());
|
||||
entitycow.renderYawOffset = this.renderYawOffset;
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
entitycow.setCustomNameTag(this.getCustomNameTag());
|
||||
}
|
||||
|
||||
this.world.spawnEntity(entitycow);
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
this.world.spawnEntity(new EntityItem(this.world, this.posX, this.posY + (double)this.height, this.posZ, new ItemStack(Blocks.RED_MUSHROOM)));
|
||||
}
|
||||
|
||||
itemstack.damageItem(1, player);
|
||||
this.playSound(SoundEvents.ENTITY_MOOSHROOM_SHEAR, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
public EntityMooshroom createChild(EntityAgeable ageable)
|
||||
{
|
||||
return new EntityMooshroom(this.world);
|
||||
}
|
||||
|
||||
@Override public boolean isShearable(ItemStack item, net.minecraft.world.IBlockAccess world, net.minecraft.util.math.BlockPos pos){ return getGrowingAge() >= 0; }
|
||||
@Override
|
||||
public java.util.List<ItemStack> onSheared(ItemStack item, net.minecraft.world.IBlockAccess world, net.minecraft.util.math.BlockPos pos, int fortune)
|
||||
{
|
||||
this.setDead();
|
||||
((net.minecraft.world.WorldServer)this.world).spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, false, this.posX, this.posY + (double)(this.height / 2.0F), this.posZ, 1, 0.0D, 0.0D, 0.0D, 0.0D);
|
||||
|
||||
EntityCow entitycow = new EntityCow(this.world);
|
||||
entitycow.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
|
||||
entitycow.setHealth(this.getHealth());
|
||||
entitycow.renderYawOffset = this.renderYawOffset;
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
entitycow.setCustomNameTag(this.getCustomNameTag());
|
||||
}
|
||||
|
||||
this.world.spawnEntity(entitycow);
|
||||
|
||||
java.util.List<ItemStack> ret = new java.util.ArrayList<ItemStack>();
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
ret.add(new ItemStack(Blocks.RED_MUSHROOM));
|
||||
}
|
||||
|
||||
this.playSound(SoundEvents.ENTITY_MOOSHROOM_SHEAR, 1.0F, 1.0F);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_MUSHROOM_COW;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityMule extends AbstractChestHorse
|
||||
{
|
||||
public EntityMule(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public static void registerFixesMule(DataFixer fixer)
|
||||
{
|
||||
AbstractChestHorse.registerFixesAbstractChestHorse(fixer, EntityMule.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_MULE;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
super.getAmbientSound();
|
||||
return SoundEvents.ENTITY_MULE_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
super.getDeathSound();
|
||||
return SoundEvents.ENTITY_MULE_DEATH;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
super.getHurtSound(damageSourceIn);
|
||||
return SoundEvents.ENTITY_MULE_HURT;
|
||||
}
|
||||
|
||||
protected void playChestEquipSound()
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_MULE_CHEST, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIAvoidEntity;
|
||||
import net.minecraft.entity.ai.EntityAIFollowOwner;
|
||||
import net.minecraft.entity.ai.EntityAILeapAtTarget;
|
||||
import net.minecraft.entity.ai.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIOcelotAttack;
|
||||
import net.minecraft.entity.ai.EntityAIOcelotSit;
|
||||
import net.minecraft.entity.ai.EntityAISit;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITargetNonTamed;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
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.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.translation.I18n;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityOcelot extends EntityTameable
|
||||
{
|
||||
private static final DataParameter<Integer> OCELOT_VARIANT = EntityDataManager.<Integer>createKey(EntityOcelot.class, DataSerializers.VARINT);
|
||||
private EntityAIAvoidEntity<EntityPlayer> avoidEntity;
|
||||
/** The tempt AI task for this mob, used to prevent taming while it is fleeing. */
|
||||
private EntityAITempt aiTempt;
|
||||
|
||||
public EntityOcelot(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.6F, 0.7F);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.aiSit = new EntityAISit(this);
|
||||
this.aiTempt = new EntityAITempt(this, 0.6D, Items.FISH, true);
|
||||
this.tasks.addTask(1, new EntityAISwimming(this));
|
||||
this.tasks.addTask(2, this.aiSit);
|
||||
this.tasks.addTask(3, this.aiTempt);
|
||||
this.tasks.addTask(5, new EntityAIFollowOwner(this, 1.0D, 10.0F, 5.0F));
|
||||
this.tasks.addTask(6, new EntityAIOcelotSit(this, 0.8D));
|
||||
this.tasks.addTask(7, new EntityAILeapAtTarget(this, 0.3F));
|
||||
this.tasks.addTask(8, new EntityAIOcelotAttack(this));
|
||||
this.tasks.addTask(9, new EntityAIMate(this, 0.8D));
|
||||
this.tasks.addTask(10, new EntityAIWanderAvoidWater(this, 0.8D, 1.0000001E-5F));
|
||||
this.tasks.addTask(11, new EntityAIWatchClosest(this, EntityPlayer.class, 10.0F));
|
||||
this.targetTasks.addTask(1, new EntityAITargetNonTamed(this, EntityChicken.class, false, (Predicate)null));
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(OCELOT_VARIANT, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public void updateAITasks()
|
||||
{
|
||||
if (this.getMoveHelper().isUpdating())
|
||||
{
|
||||
double d0 = this.getMoveHelper().getSpeed();
|
||||
|
||||
if (d0 == 0.6D)
|
||||
{
|
||||
this.setSneaking(true);
|
||||
this.setSprinting(false);
|
||||
}
|
||||
else if (d0 == 1.33D)
|
||||
{
|
||||
this.setSneaking(false);
|
||||
this.setSprinting(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setSneaking(false);
|
||||
this.setSprinting(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setSneaking(false);
|
||||
this.setSprinting(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an entity can be despawned, used on idle far away entities
|
||||
*/
|
||||
protected boolean canDespawn()
|
||||
{
|
||||
return !this.isTamed() && this.ticksExisted > 2400;
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896D);
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
public static void registerFixesOcelot(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityOcelot.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("CatType", this.getTameSkin());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setTameSkin(compound.getInteger("CatType"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
if (this.isTamed())
|
||||
{
|
||||
if (this.isInLove())
|
||||
{
|
||||
return SoundEvents.ENTITY_CAT_PURR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.rand.nextInt(4) == 0 ? SoundEvents.ENTITY_CAT_PURREOW : SoundEvents.ENTITY_CAT_AMBIENT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_CAT_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_CAT_DEATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume for the sounds this mob makes.
|
||||
*/
|
||||
protected float getSoundVolume()
|
||||
{
|
||||
return 0.4F;
|
||||
}
|
||||
|
||||
public boolean attackEntityAsMob(Entity entityIn)
|
||||
{
|
||||
return entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 3.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.aiSit != null)
|
||||
{
|
||||
this.aiSit.setSitting(false);
|
||||
}
|
||||
|
||||
return super.attackEntityFrom(source, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_OCELOT;
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (this.isTamed())
|
||||
{
|
||||
if (this.isOwner(player) && !this.world.isRemote && !this.isBreedingItem(itemstack))
|
||||
{
|
||||
this.aiSit.setSitting(!this.isSitting());
|
||||
}
|
||||
}
|
||||
else if ((this.aiTempt == null || this.aiTempt.isRunning()) && itemstack.getItem() == Items.FISH && player.getDistanceSq(this) < 9.0D)
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
if (this.rand.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, player))
|
||||
{
|
||||
this.setTamedBy(player);
|
||||
this.setTameSkin(1 + this.world.rand.nextInt(3));
|
||||
this.playTameEffect(true);
|
||||
this.aiSit.setSitting(true);
|
||||
this.world.setEntityState(this, (byte)7);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playTameEffect(false);
|
||||
this.world.setEntityState(this, (byte)6);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
|
||||
public EntityOcelot createChild(EntityAgeable ageable)
|
||||
{
|
||||
EntityOcelot entityocelot = new EntityOcelot(this.world);
|
||||
|
||||
if (this.isTamed())
|
||||
{
|
||||
entityocelot.setOwnerId(this.getOwnerId());
|
||||
entityocelot.setTamed(true);
|
||||
entityocelot.setTameSkin(this.getTameSkin());
|
||||
}
|
||||
|
||||
return entityocelot;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return stack.getItem() == Items.FISH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
if (otherAnimal == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!(otherAnimal instanceof EntityOcelot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityOcelot entityocelot = (EntityOcelot)otherAnimal;
|
||||
|
||||
if (!entityocelot.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.isInLove() && entityocelot.isInLove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getTameSkin()
|
||||
{
|
||||
return ((Integer)this.dataManager.get(OCELOT_VARIANT)).intValue();
|
||||
}
|
||||
|
||||
public void setTameSkin(int skinId)
|
||||
{
|
||||
this.dataManager.set(OCELOT_VARIANT, Integer.valueOf(skinId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
return this.world.rand.nextInt(3) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the entity is not colliding with any blocks / liquids
|
||||
*/
|
||||
public boolean isNotColliding()
|
||||
{
|
||||
if (this.world.checkNoEntityCollision(this.getEntityBoundingBox(), this) && this.world.getCollisionBoxes(this, this.getEntityBoundingBox()).isEmpty() && !this.world.containsAnyLiquid(this.getEntityBoundingBox()))
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ);
|
||||
|
||||
if (blockpos.getY() < this.world.getSeaLevel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos.down());
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (block == Blocks.GRASS || block.isLeaves(iblockstate, this.world, blockpos.down()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this object. For players this returns their username
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
return this.getCustomNameTag();
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.isTamed() ? I18n.translateToLocal("entity.Cat.name") : super.getName();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupTamedAI()
|
||||
{
|
||||
if (this.avoidEntity == null)
|
||||
{
|
||||
this.avoidEntity = new EntityAIAvoidEntity<EntityPlayer>(this, EntityPlayer.class, 16.0F, 0.8D, 1.33D);
|
||||
}
|
||||
|
||||
this.tasks.removeTask(this.avoidEntity);
|
||||
|
||||
if (!this.isTamed())
|
||||
{
|
||||
this.tasks.addTask(4, this.avoidEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
livingdata = super.onInitialSpawn(difficulty, livingdata);
|
||||
|
||||
if (this.getTameSkin() == 0 && this.world.rand.nextInt(7) == 0)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
EntityOcelot entityocelot = new EntityOcelot(this.world);
|
||||
entityocelot.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, 0.0F);
|
||||
entityocelot.setGrowingAge(-24000);
|
||||
this.world.spawnEntity(entityocelot);
|
||||
}
|
||||
}
|
||||
|
||||
return livingdata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockLeaves;
|
||||
import net.minecraft.block.BlockLog;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIFollow;
|
||||
import net.minecraft.entity.ai.EntityAIFollowOwnerFlying;
|
||||
import net.minecraft.entity.ai.EntityAILandOnOwnersShoulder;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISit;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWaterFlying;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.ai.EntityFlyHelper;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import net.minecraft.entity.monster.EntityBlaze;
|
||||
import net.minecraft.entity.monster.EntityCaveSpider;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import net.minecraft.entity.monster.EntityElderGuardian;
|
||||
import net.minecraft.entity.monster.EntityEnderman;
|
||||
import net.minecraft.entity.monster.EntityEndermite;
|
||||
import net.minecraft.entity.monster.EntityEvoker;
|
||||
import net.minecraft.entity.monster.EntityGhast;
|
||||
import net.minecraft.entity.monster.EntityHusk;
|
||||
import net.minecraft.entity.monster.EntityIllusionIllager;
|
||||
import net.minecraft.entity.monster.EntityMagmaCube;
|
||||
import net.minecraft.entity.monster.EntityPigZombie;
|
||||
import net.minecraft.entity.monster.EntityPolarBear;
|
||||
import net.minecraft.entity.monster.EntityShulker;
|
||||
import net.minecraft.entity.monster.EntitySilverfish;
|
||||
import net.minecraft.entity.monster.EntitySkeleton;
|
||||
import net.minecraft.entity.monster.EntitySlime;
|
||||
import net.minecraft.entity.monster.EntitySpider;
|
||||
import net.minecraft.entity.monster.EntityStray;
|
||||
import net.minecraft.entity.monster.EntityVex;
|
||||
import net.minecraft.entity.monster.EntityVindicator;
|
||||
import net.minecraft.entity.monster.EntityWitch;
|
||||
import net.minecraft.entity.monster.EntityWitherSkeleton;
|
||||
import net.minecraft.entity.monster.EntityZombie;
|
||||
import net.minecraft.entity.monster.EntityZombieVillager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.MobEffects;
|
||||
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.pathfinding.PathNavigate;
|
||||
import net.minecraft.pathfinding.PathNavigateFlying;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityParrot extends EntityShoulderRiding implements EntityFlying
|
||||
{
|
||||
private static final DataParameter<Integer> VARIANT = EntityDataManager.<Integer>createKey(EntityParrot.class, DataSerializers.VARINT);
|
||||
/** Used to select entities the parrot can mimic the sound of */
|
||||
private static final Predicate<EntityLiving> CAN_MIMIC = new Predicate<EntityLiving>()
|
||||
{
|
||||
public boolean apply(@Nullable EntityLiving p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != null && EntityParrot.MIMIC_SOUNDS.containsKey(p_apply_1_.getClass());
|
||||
}
|
||||
};
|
||||
private static final Item DEADLY_ITEM = Items.COOKIE;
|
||||
private static final Set<Item> TAME_ITEMS = Sets.newHashSet(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
|
||||
private static final java.util.Map<Class<? extends Entity>, SoundEvent> MIMIC_SOUNDS = Maps.newHashMapWithExpectedSize(32);
|
||||
public float flap;
|
||||
public float flapSpeed;
|
||||
public float oFlapSpeed;
|
||||
public float oFlap;
|
||||
public float flapping = 1.0F;
|
||||
private boolean partyParrot;
|
||||
private BlockPos jukeboxPosition;
|
||||
|
||||
public EntityParrot(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.5F, 0.9F);
|
||||
this.moveHelper = new EntityFlyHelper(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
this.setVariant(this.rand.nextInt(5));
|
||||
return super.onInitialSpawn(difficulty, livingdata);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.aiSit = new EntityAISit(this);
|
||||
this.tasks.addTask(0, new EntityAIPanic(this, 1.25D));
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
|
||||
this.tasks.addTask(2, this.aiSit);
|
||||
this.tasks.addTask(2, new EntityAIFollowOwnerFlying(this, 1.0D, 5.0F, 1.0F));
|
||||
this.tasks.addTask(2, new EntityAIWanderAvoidWaterFlying(this, 1.0D));
|
||||
this.tasks.addTask(3, new EntityAILandOnOwnersShoulder(this));
|
||||
this.tasks.addTask(3, new EntityAIFollow(this, 1.0D, 3.0F, 7.0F));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getAttributeMap().registerAttribute(SharedMonsterAttributes.FLYING_SPEED);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(6.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.FLYING_SPEED).setBaseValue(0.4000000059604645D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new PathNavigateGround instance
|
||||
*/
|
||||
protected PathNavigate createNavigator(World worldIn)
|
||||
{
|
||||
PathNavigateFlying pathnavigateflying = new PathNavigateFlying(this, worldIn);
|
||||
pathnavigateflying.setCanOpenDoors(false);
|
||||
pathnavigateflying.setCanFloat(true);
|
||||
pathnavigateflying.setCanEnterDoors(true);
|
||||
return pathnavigateflying;
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.height * 0.6F;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
playMimicSound(this.world, this);
|
||||
|
||||
if (this.jukeboxPosition == null || this.jukeboxPosition.distanceSq(this.posX, this.posY, this.posZ) > 12.0D || this.world.getBlockState(this.jukeboxPosition).getBlock() != Blocks.JUKEBOX)
|
||||
{
|
||||
this.partyParrot = false;
|
||||
this.jukeboxPosition = null;
|
||||
}
|
||||
|
||||
super.onLivingUpdate();
|
||||
this.calculateFlapping();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void setPartying(BlockPos pos, boolean p_191987_2_)
|
||||
{
|
||||
this.jukeboxPosition = pos;
|
||||
this.partyParrot = p_191987_2_;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isPartying()
|
||||
{
|
||||
return this.partyParrot;
|
||||
}
|
||||
|
||||
private void calculateFlapping()
|
||||
{
|
||||
this.oFlap = this.flap;
|
||||
this.oFlapSpeed = this.flapSpeed;
|
||||
this.flapSpeed = (float)((double)this.flapSpeed + (double)(this.onGround ? -1 : 4) * 0.3D);
|
||||
this.flapSpeed = MathHelper.clamp(this.flapSpeed, 0.0F, 1.0F);
|
||||
|
||||
if (!this.onGround && this.flapping < 1.0F)
|
||||
{
|
||||
this.flapping = 1.0F;
|
||||
}
|
||||
|
||||
this.flapping = (float)((double)this.flapping * 0.9D);
|
||||
|
||||
if (!this.onGround && this.motionY < 0.0D)
|
||||
{
|
||||
this.motionY *= 0.6D;
|
||||
}
|
||||
|
||||
this.flap += this.flapping * 2.0F;
|
||||
}
|
||||
|
||||
private static boolean playMimicSound(World worldIn, Entity p_192006_1_)
|
||||
{
|
||||
if (!p_192006_1_.isSilent() && worldIn.rand.nextInt(50) == 0)
|
||||
{
|
||||
List<EntityLiving> list = worldIn.<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, p_192006_1_.getEntityBoundingBox().grow(20.0D), CAN_MIMIC);
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
EntityLiving entityliving = list.get(worldIn.rand.nextInt(list.size()));
|
||||
|
||||
if (!entityliving.isSilent())
|
||||
{
|
||||
SoundEvent soundevent = MIMIC_SOUNDS.get(entityliving.getClass());
|
||||
worldIn.playSound((EntityPlayer)null, p_192006_1_.posX, p_192006_1_.posY, p_192006_1_.posZ, soundevent, p_192006_1_.getSoundCategory(), 0.7F, getPitch(worldIn.rand));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (!this.isTamed() && TAME_ITEMS.contains(itemstack.getItem()))
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
if (!this.isSilent())
|
||||
{
|
||||
this.world.playSound((EntityPlayer)null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PARROT_EAT, this.getSoundCategory(), 1.0F, 1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
if (this.rand.nextInt(10) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, player))
|
||||
{
|
||||
this.setTamedBy(player);
|
||||
this.playTameEffect(true);
|
||||
this.world.setEntityState(this, (byte)7);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playTameEffect(false);
|
||||
this.world.setEntityState(this, (byte)6);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (itemstack.getItem() == DEADLY_ITEM)
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
this.addPotionEffect(new PotionEffect(MobEffects.POISON, 900));
|
||||
|
||||
if (player.isCreative() || !this.getIsInvulnerable())
|
||||
{
|
||||
this.attackEntityFrom(DamageSource.causePlayerDamage(player), Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.world.isRemote && !this.isFlying() && this.isTamed() && this.isOwner(player))
|
||||
{
|
||||
this.aiSit.setSitting(!this.isSitting());
|
||||
}
|
||||
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
int i = MathHelper.floor(this.posX);
|
||||
int j = MathHelper.floor(this.getEntityBoundingBox().minY);
|
||||
int k = MathHelper.floor(this.posZ);
|
||||
BlockPos blockpos = new BlockPos(i, j, k);
|
||||
Block block = this.world.getBlockState(blockpos.down()).getBlock();
|
||||
return block instanceof BlockLeaves || block == Blocks.GRASS || block instanceof BlockLog || block == Blocks.AIR && this.world.getLight(blockpos) > 8 && super.getCanSpawnHere();
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityAgeable createChild(EntityAgeable ageable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void playAmbientSound(World worldIn, Entity p_192005_1_)
|
||||
{
|
||||
if (!p_192005_1_.isSilent() && !playMimicSound(worldIn, p_192005_1_) && worldIn.rand.nextInt(200) == 0)
|
||||
{
|
||||
worldIn.playSound((EntityPlayer)null, p_192005_1_.posX, p_192005_1_.posY, p_192005_1_.posZ, getAmbientSound(worldIn.rand), p_192005_1_.getSoundCategory(), 1.0F, getPitch(worldIn.rand));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean attackEntityAsMob(Entity entityIn)
|
||||
{
|
||||
return entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 3.0F);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SoundEvent getAmbientSound()
|
||||
{
|
||||
return getAmbientSound(this.rand);
|
||||
}
|
||||
|
||||
private static SoundEvent getAmbientSound(Random random)
|
||||
{
|
||||
if (random.nextInt(1000) == 0)
|
||||
{
|
||||
List<SoundEvent> list = new ArrayList<SoundEvent>(MIMIC_SOUNDS.values());
|
||||
SoundEvent ret = list.get(random.nextInt(list.size()));
|
||||
return ret == null ? SoundEvents.ENTITY_PARROT_AMBIENT : ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SoundEvents.ENTITY_PARROT_AMBIENT;
|
||||
}
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_PARROT_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_PARROT_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_PARROT_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
protected float playFlySound(float p_191954_1_)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_PARROT_FLY, 0.15F, 1.0F);
|
||||
return p_191954_1_ + this.flapSpeed / 2.0F;
|
||||
}
|
||||
|
||||
protected boolean makeFlySound()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pitch of living sounds in living entities.
|
||||
*/
|
||||
protected float getSoundPitch()
|
||||
{
|
||||
return getPitch(this.rand);
|
||||
}
|
||||
|
||||
private static float getPitch(Random random)
|
||||
{
|
||||
return (random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F;
|
||||
}
|
||||
|
||||
public SoundCategory getSoundCategory()
|
||||
{
|
||||
return SoundCategory.NEUTRAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this entity should push and be pushed by other entities when colliding.
|
||||
*/
|
||||
public boolean canBePushed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void collideWithEntity(Entity entityIn)
|
||||
{
|
||||
if (!(entityIn instanceof EntityPlayer))
|
||||
{
|
||||
super.collideWithEntity(entityIn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.aiSit != null)
|
||||
{
|
||||
this.aiSit.setSitting(false);
|
||||
}
|
||||
|
||||
return super.attackEntityFrom(source, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public int getVariant()
|
||||
{
|
||||
return MathHelper.clamp(((Integer)this.dataManager.get(VARIANT)).intValue(), 0, 4);
|
||||
}
|
||||
|
||||
public void setVariant(int p_191997_1_)
|
||||
{
|
||||
this.dataManager.set(VARIANT, Integer.valueOf(p_191997_1_));
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(VARIANT, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("Variant", this.getVariant());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setVariant(compound.getInteger("Variant"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_PARROT;
|
||||
}
|
||||
|
||||
public boolean isFlying()
|
||||
{
|
||||
return !this.onGround;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
registerMimicSound(EntityBlaze.class, SoundEvents.E_PARROT_IM_BLAZE);
|
||||
registerMimicSound(EntityCaveSpider.class, SoundEvents.E_PARROT_IM_SPIDER);
|
||||
registerMimicSound(EntityCreeper.class, SoundEvents.E_PARROT_IM_CREEPER);
|
||||
registerMimicSound(EntityElderGuardian.class, SoundEvents.E_PARROT_IM_ELDER_GUARDIAN);
|
||||
registerMimicSound(EntityDragon.class, SoundEvents.E_PARROT_IM_ENDERDRAGON);
|
||||
registerMimicSound(EntityEnderman.class, SoundEvents.E_PARROT_IM_ENDERMAN);
|
||||
registerMimicSound(EntityEndermite.class, SoundEvents.E_PARROT_IM_ENDERMITE);
|
||||
registerMimicSound(EntityEvoker.class, SoundEvents.E_PARROT_IM_EVOCATION_ILLAGER);
|
||||
registerMimicSound(EntityGhast.class, SoundEvents.E_PARROT_IM_GHAST);
|
||||
registerMimicSound(EntityHusk.class, SoundEvents.E_PARROT_IM_HUSK);
|
||||
registerMimicSound(EntityIllusionIllager.class, SoundEvents.E_PARROT_IM_ILLUSION_ILLAGER);
|
||||
registerMimicSound(EntityMagmaCube.class, SoundEvents.E_PARROT_IM_MAGMACUBE);
|
||||
registerMimicSound(EntityPigZombie.class, SoundEvents.E_PARROT_IM_ZOMBIE_PIGMAN);
|
||||
registerMimicSound(EntityPolarBear.class, SoundEvents.E_PARROT_IM_POLAR_BEAR);
|
||||
registerMimicSound(EntityShulker.class, SoundEvents.E_PARROT_IM_SHULKER);
|
||||
registerMimicSound(EntitySilverfish.class, SoundEvents.E_PARROT_IM_SILVERFISH);
|
||||
registerMimicSound(EntitySkeleton.class, SoundEvents.E_PARROT_IM_SKELETON);
|
||||
registerMimicSound(EntitySlime.class, SoundEvents.E_PARROT_IM_SLIME);
|
||||
registerMimicSound(EntitySpider.class, SoundEvents.E_PARROT_IM_SPIDER);
|
||||
registerMimicSound(EntityStray.class, SoundEvents.E_PARROT_IM_STRAY);
|
||||
registerMimicSound(EntityVex.class, SoundEvents.E_PARROT_IM_VEX);
|
||||
registerMimicSound(EntityVindicator.class, SoundEvents.E_PARROT_IM_VINDICATION_ILLAGER);
|
||||
registerMimicSound(EntityWitch.class, SoundEvents.E_PARROT_IM_WITCH);
|
||||
registerMimicSound(EntityWither.class, SoundEvents.E_PARROT_IM_WITHER);
|
||||
registerMimicSound(EntityWitherSkeleton.class, SoundEvents.E_PARROT_IM_WITHER_SKELETON);
|
||||
registerMimicSound(EntityWolf.class, SoundEvents.E_PARROT_IM_WOLF);
|
||||
registerMimicSound(EntityZombie.class, SoundEvents.E_PARROT_IM_ZOMBIE);
|
||||
registerMimicSound(EntityZombieVillager.class, SoundEvents.E_PARROT_IM_ZOMBIE_VILLAGER);
|
||||
}
|
||||
|
||||
public static void registerMimicSound(Class<? extends Entity> cls, SoundEvent sound)
|
||||
{
|
||||
MIMIC_SOUNDS.put(cls, sound);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIFollowParent;
|
||||
import net.minecraft.entity.ai.EntityAILookIdle;
|
||||
import net.minecraft.entity.ai.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.effect.EntityLightningBolt;
|
||||
import net.minecraft.entity.monster.EntityPigZombie;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
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.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityPig extends EntityAnimal
|
||||
{
|
||||
private static final DataParameter<Boolean> SADDLED = EntityDataManager.<Boolean>createKey(EntityPig.class, DataSerializers.BOOLEAN);
|
||||
private static final DataParameter<Integer> BOOST_TIME = EntityDataManager.<Integer>createKey(EntityPig.class, DataSerializers.VARINT);
|
||||
private static final Set<Item> TEMPTATION_ITEMS = Sets.newHashSet(Items.CARROT, Items.POTATO, Items.BEETROOT);
|
||||
private boolean boosting;
|
||||
private int boostTime;
|
||||
private int totalBoostTime;
|
||||
|
||||
public EntityPig(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.9F, 0.9F);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIPanic(this, 1.25D));
|
||||
this.tasks.addTask(3, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(4, new EntityAITempt(this, 1.2D, Items.CARROT_ON_A_STICK, false));
|
||||
this.tasks.addTask(4, new EntityAITempt(this, 1.2D, false, TEMPTATION_ITEMS));
|
||||
this.tasks.addTask(5, new EntityAIFollowParent(this, 1.1D));
|
||||
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 1.0D));
|
||||
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(8, new EntityAILookIdle(this));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.25D);
|
||||
}
|
||||
|
||||
/**
|
||||
* For vehicles, the first passenger is generally considered the controller and "drives" the vehicle. For example,
|
||||
* Pigs, Horses, and Boats are generally "steered" by the controlling passenger.
|
||||
*/
|
||||
@Nullable
|
||||
public Entity getControllingPassenger()
|
||||
{
|
||||
return this.getPassengers().isEmpty() ? null : (Entity)this.getPassengers().get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if all the conditions for steering the entity are met. For pigs, this is true if it is being ridden
|
||||
* by a player and the player is holding a carrot-on-a-stick
|
||||
*/
|
||||
public boolean canBeSteered()
|
||||
{
|
||||
Entity entity = this.getControllingPassenger();
|
||||
|
||||
if (!(entity instanceof EntityPlayer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityPlayer entityplayer = (EntityPlayer)entity;
|
||||
return entityplayer.getHeldItemMainhand().getItem() == Items.CARROT_ON_A_STICK || entityplayer.getHeldItemOffhand().getItem() == Items.CARROT_ON_A_STICK;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyDataManagerChange(DataParameter<?> key)
|
||||
{
|
||||
if (BOOST_TIME.equals(key) && this.world.isRemote)
|
||||
{
|
||||
this.boosting = true;
|
||||
this.boostTime = 0;
|
||||
this.totalBoostTime = ((Integer)this.dataManager.get(BOOST_TIME)).intValue();
|
||||
}
|
||||
|
||||
super.notifyDataManagerChange(key);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(SADDLED, Boolean.valueOf(false));
|
||||
this.dataManager.register(BOOST_TIME, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public static void registerFixesPig(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityPig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("Saddle", this.getSaddled());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setSaddled(compound.getBoolean("Saddle"));
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_PIG_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_PIG_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_PIG_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_PIG_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
if (!super.processInteract(player, hand))
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (itemstack.getItem() == Items.NAME_TAG)
|
||||
{
|
||||
itemstack.interactWithEntity(player, this, hand);
|
||||
return true;
|
||||
}
|
||||
else if (this.getSaddled() && !this.isBeingRidden())
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
player.startRiding(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (itemstack.getItem() == Items.SADDLE)
|
||||
{
|
||||
itemstack.interactWithEntity(player, this, hand);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mob's health reaches 0.
|
||||
*/
|
||||
public void onDeath(DamageSource cause)
|
||||
{
|
||||
super.onDeath(cause);
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
if (this.getSaddled())
|
||||
{
|
||||
this.dropItem(Items.SADDLE, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_PIG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the pig is saddled.
|
||||
*/
|
||||
public boolean getSaddled()
|
||||
{
|
||||
return ((Boolean)this.dataManager.get(SADDLED)).booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or remove the saddle of the pig.
|
||||
*/
|
||||
public void setSaddled(boolean saddled)
|
||||
{
|
||||
if (saddled)
|
||||
{
|
||||
this.dataManager.set(SADDLED, Boolean.valueOf(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(SADDLED, Boolean.valueOf(false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a lightning bolt hits the entity.
|
||||
*/
|
||||
public void onStruckByLightning(EntityLightningBolt lightningBolt)
|
||||
{
|
||||
if (!this.world.isRemote && !this.isDead)
|
||||
{
|
||||
EntityPigZombie entitypigzombie = new EntityPigZombie(this.world);
|
||||
entitypigzombie.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(Items.GOLDEN_SWORD));
|
||||
entitypigzombie.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
|
||||
entitypigzombie.setNoAI(this.isAIDisabled());
|
||||
|
||||
if (this.hasCustomName())
|
||||
{
|
||||
entitypigzombie.setCustomNameTag(this.getCustomNameTag());
|
||||
entitypigzombie.setAlwaysRenderNameTag(this.getAlwaysRenderNameTag());
|
||||
}
|
||||
|
||||
this.world.spawnEntity(entitypigzombie);
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
public void travel(float strafe, float vertical, float forward)
|
||||
{
|
||||
Entity entity = this.getPassengers().isEmpty() ? null : (Entity)this.getPassengers().get(0);
|
||||
|
||||
if (this.isBeingRidden() && this.canBeSteered())
|
||||
{
|
||||
this.rotationYaw = entity.rotationYaw;
|
||||
this.prevRotationYaw = this.rotationYaw;
|
||||
this.rotationPitch = entity.rotationPitch * 0.5F;
|
||||
this.setRotation(this.rotationYaw, this.rotationPitch);
|
||||
this.renderYawOffset = this.rotationYaw;
|
||||
this.rotationYawHead = this.rotationYaw;
|
||||
this.stepHeight = 1.0F;
|
||||
this.jumpMovementFactor = this.getAIMoveSpeed() * 0.1F;
|
||||
|
||||
if (this.boosting && this.boostTime++ > this.totalBoostTime)
|
||||
{
|
||||
this.boosting = false;
|
||||
}
|
||||
|
||||
if (this.canPassengerSteer())
|
||||
{
|
||||
float f = (float)this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getAttributeValue() * 0.225F;
|
||||
|
||||
if (this.boosting)
|
||||
{
|
||||
f += f * 1.15F * MathHelper.sin((float)this.boostTime / (float)this.totalBoostTime * (float)Math.PI);
|
||||
}
|
||||
|
||||
this.setAIMoveSpeed(f);
|
||||
super.travel(0.0F, 0.0F, 1.0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.motionX = 0.0D;
|
||||
this.motionY = 0.0D;
|
||||
this.motionZ = 0.0D;
|
||||
}
|
||||
|
||||
this.prevLimbSwingAmount = this.limbSwingAmount;
|
||||
double d1 = this.posX - this.prevPosX;
|
||||
double d0 = this.posZ - this.prevPosZ;
|
||||
float f1 = MathHelper.sqrt(d1 * d1 + d0 * d0) * 4.0F;
|
||||
|
||||
if (f1 > 1.0F)
|
||||
{
|
||||
f1 = 1.0F;
|
||||
}
|
||||
|
||||
this.limbSwingAmount += (f1 - this.limbSwingAmount) * 0.4F;
|
||||
this.limbSwing += this.limbSwingAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.stepHeight = 0.5F;
|
||||
this.jumpMovementFactor = 0.02F;
|
||||
super.travel(strafe, vertical, forward);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean boost()
|
||||
{
|
||||
if (this.boosting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.boosting = true;
|
||||
this.boostTime = 0;
|
||||
this.totalBoostTime = this.getRNG().nextInt(841) + 140;
|
||||
this.getDataManager().set(BOOST_TIME, Integer.valueOf(this.totalBoostTime));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public EntityPig createChild(EntityAgeable ageable)
|
||||
{
|
||||
return new EntityPig(this.world);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return TEMPTATION_ITEMS.contains(stack.getItem());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,771 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockCarrot;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
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.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIMoveToBlock;
|
||||
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.ai.EntityJumpHelper;
|
||||
import net.minecraft.entity.ai.EntityMoveHelper;
|
||||
import net.minecraft.entity.monster.EntityMob;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
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.pathfinding.Path;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.translation.I18n;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeDesert;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityRabbit extends EntityAnimal
|
||||
{
|
||||
private static final DataParameter<Integer> RABBIT_TYPE = EntityDataManager.<Integer>createKey(EntityRabbit.class, DataSerializers.VARINT);
|
||||
private int jumpTicks;
|
||||
private int jumpDuration;
|
||||
private boolean wasOnGround;
|
||||
private int currentMoveTypeDuration;
|
||||
private int carrotTicks;
|
||||
|
||||
public EntityRabbit(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.4F, 0.5F);
|
||||
this.jumpHelper = new EntityRabbit.RabbitJumpHelper(this);
|
||||
this.moveHelper = new EntityRabbit.RabbitMoveHelper(this);
|
||||
this.setMovementSpeed(0.0D);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(1, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityRabbit.AIPanic(this, 2.2D));
|
||||
this.tasks.addTask(2, new EntityAIMate(this, 0.8D));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.0D, Items.CARROT, false));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.0D, Items.GOLDEN_CARROT, false));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.0D, Item.getItemFromBlock(Blocks.YELLOW_FLOWER), false));
|
||||
this.tasks.addTask(4, new EntityRabbit.AIAvoidEntity(this, EntityPlayer.class, 8.0F, 2.2D, 2.2D));
|
||||
this.tasks.addTask(4, new EntityRabbit.AIAvoidEntity(this, EntityWolf.class, 10.0F, 2.2D, 2.2D));
|
||||
this.tasks.addTask(4, new EntityRabbit.AIAvoidEntity(this, EntityMob.class, 4.0F, 2.2D, 2.2D));
|
||||
this.tasks.addTask(5, new EntityRabbit.AIRaidFarm(this));
|
||||
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 0.6D));
|
||||
this.tasks.addTask(11, new EntityAIWatchClosest(this, EntityPlayer.class, 10.0F));
|
||||
}
|
||||
|
||||
protected float getJumpUpwardsMotion()
|
||||
{
|
||||
if (!this.collidedHorizontally && (!this.moveHelper.isUpdating() || this.moveHelper.getY() <= this.posY + 0.5D))
|
||||
{
|
||||
Path path = this.navigator.getPath();
|
||||
|
||||
if (path != null && path.getCurrentPathIndex() < path.getCurrentPathLength())
|
||||
{
|
||||
Vec3d vec3d = path.getPosition(this);
|
||||
|
||||
if (vec3d.y > this.posY + 0.5D)
|
||||
{
|
||||
return 0.5F;
|
||||
}
|
||||
}
|
||||
|
||||
return this.moveHelper.getSpeed() <= 0.6D ? 0.2F : 0.3F;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.5F;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes this entity to do an upwards motion (jumping).
|
||||
*/
|
||||
protected void jump()
|
||||
{
|
||||
super.jump();
|
||||
double d0 = this.moveHelper.getSpeed();
|
||||
|
||||
if (d0 > 0.0D)
|
||||
{
|
||||
double d1 = this.motionX * this.motionX + this.motionZ * this.motionZ;
|
||||
|
||||
if (d1 < 0.010000000000000002D)
|
||||
{
|
||||
this.moveRelative(0.0F, 0.0F, 1.0F, 0.1F);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.world.setEntityState(this, (byte)1);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float setJumpCompletion(float p_175521_1_)
|
||||
{
|
||||
return this.jumpDuration == 0 ? 0.0F : ((float)this.jumpTicks + p_175521_1_) / (float)this.jumpDuration;
|
||||
}
|
||||
|
||||
public void setMovementSpeed(double newSpeed)
|
||||
{
|
||||
this.getNavigator().setSpeed(newSpeed);
|
||||
this.moveHelper.setMoveTo(this.moveHelper.getX(), this.moveHelper.getY(), this.moveHelper.getZ(), newSpeed);
|
||||
}
|
||||
|
||||
public void setJumping(boolean jumping)
|
||||
{
|
||||
super.setJumping(jumping);
|
||||
|
||||
if (jumping)
|
||||
{
|
||||
this.playSound(this.getJumpSound(), this.getSoundVolume(), ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F) * 0.8F);
|
||||
}
|
||||
}
|
||||
|
||||
public void startJumping()
|
||||
{
|
||||
this.setJumping(true);
|
||||
this.jumpDuration = 10;
|
||||
this.jumpTicks = 0;
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(RABBIT_TYPE, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public void updateAITasks()
|
||||
{
|
||||
if (this.currentMoveTypeDuration > 0)
|
||||
{
|
||||
--this.currentMoveTypeDuration;
|
||||
}
|
||||
|
||||
if (this.carrotTicks > 0)
|
||||
{
|
||||
this.carrotTicks -= this.rand.nextInt(3);
|
||||
|
||||
if (this.carrotTicks < 0)
|
||||
{
|
||||
this.carrotTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onGround)
|
||||
{
|
||||
if (!this.wasOnGround)
|
||||
{
|
||||
this.setJumping(false);
|
||||
this.checkLandingDelay();
|
||||
}
|
||||
|
||||
if (this.getRabbitType() == 99 && this.currentMoveTypeDuration == 0)
|
||||
{
|
||||
EntityLivingBase entitylivingbase = this.getAttackTarget();
|
||||
|
||||
if (entitylivingbase != null && this.getDistanceSq(entitylivingbase) < 16.0D)
|
||||
{
|
||||
this.calculateRotationYaw(entitylivingbase.posX, entitylivingbase.posZ);
|
||||
this.moveHelper.setMoveTo(entitylivingbase.posX, entitylivingbase.posY, entitylivingbase.posZ, this.moveHelper.getSpeed());
|
||||
this.startJumping();
|
||||
this.wasOnGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
EntityRabbit.RabbitJumpHelper entityrabbit$rabbitjumphelper = (EntityRabbit.RabbitJumpHelper)this.jumpHelper;
|
||||
|
||||
if (!entityrabbit$rabbitjumphelper.getIsJumping())
|
||||
{
|
||||
if (this.moveHelper.isUpdating() && this.currentMoveTypeDuration == 0)
|
||||
{
|
||||
Path path = this.navigator.getPath();
|
||||
Vec3d vec3d = new Vec3d(this.moveHelper.getX(), this.moveHelper.getY(), this.moveHelper.getZ());
|
||||
|
||||
if (path != null && path.getCurrentPathIndex() < path.getCurrentPathLength())
|
||||
{
|
||||
vec3d = path.getPosition(this);
|
||||
}
|
||||
|
||||
this.calculateRotationYaw(vec3d.x, vec3d.z);
|
||||
this.startJumping();
|
||||
}
|
||||
}
|
||||
else if (!entityrabbit$rabbitjumphelper.canJump())
|
||||
{
|
||||
this.enableJumpControl();
|
||||
}
|
||||
}
|
||||
|
||||
this.wasOnGround = this.onGround;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create sprinting particles if the entity is sprinting and not in water.
|
||||
*/
|
||||
public void spawnRunningParticles()
|
||||
{
|
||||
}
|
||||
|
||||
private void calculateRotationYaw(double x, double z)
|
||||
{
|
||||
this.rotationYaw = (float)(MathHelper.atan2(z - this.posZ, x - this.posX) * (180D / Math.PI)) - 90.0F;
|
||||
}
|
||||
|
||||
private void enableJumpControl()
|
||||
{
|
||||
((EntityRabbit.RabbitJumpHelper)this.jumpHelper).setCanJump(true);
|
||||
}
|
||||
|
||||
private void disableJumpControl()
|
||||
{
|
||||
((EntityRabbit.RabbitJumpHelper)this.jumpHelper).setCanJump(false);
|
||||
}
|
||||
|
||||
private void updateMoveTypeDuration()
|
||||
{
|
||||
if (this.moveHelper.getSpeed() < 2.2D)
|
||||
{
|
||||
this.currentMoveTypeDuration = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentMoveTypeDuration = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLandingDelay()
|
||||
{
|
||||
this.updateMoveTypeDuration();
|
||||
this.disableJumpControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
|
||||
if (this.jumpTicks != this.jumpDuration)
|
||||
{
|
||||
++this.jumpTicks;
|
||||
}
|
||||
else if (this.jumpDuration != 0)
|
||||
{
|
||||
this.jumpTicks = 0;
|
||||
this.jumpDuration = 0;
|
||||
this.setJumping(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(3.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896D);
|
||||
}
|
||||
|
||||
public static void registerFixesRabbit(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityRabbit.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("RabbitType", this.getRabbitType());
|
||||
compound.setInteger("MoreCarrotTicks", this.carrotTicks);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setRabbitType(compound.getInteger("RabbitType"));
|
||||
this.carrotTicks = compound.getInteger("MoreCarrotTicks");
|
||||
}
|
||||
|
||||
protected SoundEvent getJumpSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_RABBIT_JUMP;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_RABBIT_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_RABBIT_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_RABBIT_DEATH;
|
||||
}
|
||||
|
||||
public boolean attackEntityAsMob(Entity entityIn)
|
||||
{
|
||||
if (this.getRabbitType() == 99)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_RABBIT_ATTACK, 1.0F, (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
return entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 8.0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 3.0F);
|
||||
}
|
||||
}
|
||||
|
||||
public SoundCategory getSoundCategory()
|
||||
{
|
||||
return this.getRabbitType() == 99 ? SoundCategory.HOSTILE : SoundCategory.NEUTRAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
return this.isEntityInvulnerable(source) ? false : super.attackEntityFrom(source, amount);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_RABBIT;
|
||||
}
|
||||
|
||||
private boolean isRabbitBreedingItem(Item itemIn)
|
||||
{
|
||||
return itemIn == Items.CARROT || itemIn == Items.GOLDEN_CARROT || itemIn == Item.getItemFromBlock(Blocks.YELLOW_FLOWER);
|
||||
}
|
||||
|
||||
public EntityRabbit createChild(EntityAgeable ageable)
|
||||
{
|
||||
EntityRabbit entityrabbit = new EntityRabbit(this.world);
|
||||
int i = this.getRandomRabbitType();
|
||||
|
||||
if (this.rand.nextInt(20) != 0)
|
||||
{
|
||||
if (ageable instanceof EntityRabbit && this.rand.nextBoolean())
|
||||
{
|
||||
i = ((EntityRabbit)ageable).getRabbitType();
|
||||
}
|
||||
else
|
||||
{
|
||||
i = this.getRabbitType();
|
||||
}
|
||||
}
|
||||
|
||||
entityrabbit.setRabbitType(i);
|
||||
return entityrabbit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return this.isRabbitBreedingItem(stack.getItem());
|
||||
}
|
||||
|
||||
public int getRabbitType()
|
||||
{
|
||||
return ((Integer)this.dataManager.get(RABBIT_TYPE)).intValue();
|
||||
}
|
||||
|
||||
public void setRabbitType(int rabbitTypeId)
|
||||
{
|
||||
if (rabbitTypeId == 99)
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(8.0D);
|
||||
this.tasks.addTask(4, new EntityRabbit.AIEvilAttack(this));
|
||||
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false, new Class[0]));
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, true));
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityWolf.class, true));
|
||||
|
||||
if (!this.hasCustomName())
|
||||
{
|
||||
this.setCustomNameTag(I18n.translateToLocal("entity.KillerBunny.name"));
|
||||
}
|
||||
}
|
||||
|
||||
this.dataManager.set(RABBIT_TYPE, Integer.valueOf(rabbitTypeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
livingdata = super.onInitialSpawn(difficulty, livingdata);
|
||||
int i = this.getRandomRabbitType();
|
||||
boolean flag = false;
|
||||
|
||||
if (livingdata instanceof EntityRabbit.RabbitTypeData)
|
||||
{
|
||||
i = ((EntityRabbit.RabbitTypeData)livingdata).typeData;
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
livingdata = new EntityRabbit.RabbitTypeData(i);
|
||||
}
|
||||
|
||||
this.setRabbitType(i);
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.setGrowingAge(-24000);
|
||||
}
|
||||
|
||||
return livingdata;
|
||||
}
|
||||
|
||||
private int getRandomRabbitType()
|
||||
{
|
||||
Biome biome = this.world.getBiome(new BlockPos(this));
|
||||
int i = this.rand.nextInt(100);
|
||||
|
||||
if (biome.isSnowyBiome())
|
||||
{
|
||||
return i < 80 ? 1 : 3;
|
||||
}
|
||||
else if (biome instanceof BiomeDesert)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return i < 50 ? 0 : (i < 90 ? 5 : 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link net.minecraft.entity.passive.EntityRabbit#carrotTicks carrotTicks} has reached zero
|
||||
*/
|
||||
private boolean isCarrotEaten()
|
||||
{
|
||||
return this.carrotTicks == 0;
|
||||
}
|
||||
|
||||
protected void createEatingParticles()
|
||||
{
|
||||
BlockCarrot blockcarrot = (BlockCarrot)Blocks.CARROTS;
|
||||
IBlockState iblockstate = blockcarrot.withAge(blockcarrot.getMaxAge());
|
||||
this.world.spawnParticle(EnumParticleTypes.BLOCK_DUST, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, 0.0D, 0.0D, 0.0D, Block.getStateId(iblockstate));
|
||||
this.carrotTicks = 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 1)
|
||||
{
|
||||
this.createRunningParticles();
|
||||
this.jumpDuration = 10;
|
||||
this.jumpTicks = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
|
||||
static class AIAvoidEntity<T extends Entity> extends EntityAIAvoidEntity<T>
|
||||
{
|
||||
private final EntityRabbit rabbit;
|
||||
|
||||
public AIAvoidEntity(EntityRabbit rabbit, Class<T> p_i46403_2_, float p_i46403_3_, double p_i46403_4_, double p_i46403_6_)
|
||||
{
|
||||
super(rabbit, p_i46403_2_, p_i46403_3_, p_i46403_4_, p_i46403_6_);
|
||||
this.rabbit = rabbit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return this.rabbit.getRabbitType() != 99 && super.shouldExecute();
|
||||
}
|
||||
}
|
||||
|
||||
static class AIEvilAttack extends EntityAIAttackMelee
|
||||
{
|
||||
public AIEvilAttack(EntityRabbit rabbit)
|
||||
{
|
||||
super(rabbit, 1.4D, true);
|
||||
}
|
||||
|
||||
protected double getAttackReachSqr(EntityLivingBase attackTarget)
|
||||
{
|
||||
return (double)(4.0F + attackTarget.width);
|
||||
}
|
||||
}
|
||||
|
||||
static class AIPanic extends EntityAIPanic
|
||||
{
|
||||
private final EntityRabbit rabbit;
|
||||
|
||||
public AIPanic(EntityRabbit rabbit, double speedIn)
|
||||
{
|
||||
super(rabbit, speedIn);
|
||||
this.rabbit = rabbit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep ticking a continuous task that has already been started
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
super.updateTask();
|
||||
this.rabbit.setMovementSpeed(this.speed);
|
||||
}
|
||||
}
|
||||
|
||||
static class AIRaidFarm extends EntityAIMoveToBlock
|
||||
{
|
||||
private final EntityRabbit rabbit;
|
||||
private boolean wantsToRaid;
|
||||
private boolean canRaid;
|
||||
|
||||
public AIRaidFarm(EntityRabbit rabbitIn)
|
||||
{
|
||||
super(rabbitIn, 0.699999988079071D, 16);
|
||||
this.rabbit = rabbitIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (this.runDelay <= 0)
|
||||
{
|
||||
if (!net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.rabbit.world, this.rabbit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.canRaid = false;
|
||||
this.wantsToRaid = this.rabbit.isCarrotEaten();
|
||||
this.wantsToRaid = true;
|
||||
}
|
||||
|
||||
return super.shouldExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an in-progress EntityAIBase should continue executing
|
||||
*/
|
||||
public boolean shouldContinueExecuting()
|
||||
{
|
||||
return this.canRaid && super.shouldContinueExecuting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep ticking a continuous task that has already been started
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
super.updateTask();
|
||||
this.rabbit.getLookHelper().setLookPosition((double)this.destinationBlock.getX() + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)this.destinationBlock.getZ() + 0.5D, 10.0F, (float)this.rabbit.getVerticalFaceSpeed());
|
||||
|
||||
if (this.getIsAboveDestination())
|
||||
{
|
||||
World world = this.rabbit.world;
|
||||
BlockPos blockpos = this.destinationBlock.up();
|
||||
IBlockState iblockstate = world.getBlockState(blockpos);
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (this.canRaid && block instanceof BlockCarrot)
|
||||
{
|
||||
Integer integer = (Integer)iblockstate.getValue(BlockCarrot.AGE);
|
||||
|
||||
if (integer.intValue() == 0)
|
||||
{
|
||||
world.setBlockState(blockpos, Blocks.AIR.getDefaultState(), 2);
|
||||
world.destroyBlock(blockpos, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
world.setBlockState(blockpos, iblockstate.withProperty(BlockCarrot.AGE, Integer.valueOf(integer.intValue() - 1)), 2);
|
||||
world.playEvent(2001, blockpos, Block.getStateId(iblockstate));
|
||||
}
|
||||
|
||||
this.rabbit.createEatingParticles();
|
||||
}
|
||||
|
||||
this.canRaid = false;
|
||||
this.runDelay = 10;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to set given position as destination
|
||||
*/
|
||||
protected boolean shouldMoveTo(World worldIn, BlockPos pos)
|
||||
{
|
||||
Block block = worldIn.getBlockState(pos).getBlock();
|
||||
|
||||
if (block == Blocks.FARMLAND && this.wantsToRaid && !this.canRaid)
|
||||
{
|
||||
pos = pos.up();
|
||||
IBlockState iblockstate = worldIn.getBlockState(pos);
|
||||
block = iblockstate.getBlock();
|
||||
|
||||
if (block instanceof BlockCarrot && ((BlockCarrot)block).isMaxAge(iblockstate))
|
||||
{
|
||||
this.canRaid = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class RabbitJumpHelper extends EntityJumpHelper
|
||||
{
|
||||
private final EntityRabbit rabbit;
|
||||
private boolean canJump;
|
||||
|
||||
public RabbitJumpHelper(EntityRabbit rabbit)
|
||||
{
|
||||
super(rabbit);
|
||||
this.rabbit = rabbit;
|
||||
}
|
||||
|
||||
public boolean getIsJumping()
|
||||
{
|
||||
return this.isJumping;
|
||||
}
|
||||
|
||||
public boolean canJump()
|
||||
{
|
||||
return this.canJump;
|
||||
}
|
||||
|
||||
public void setCanJump(boolean canJumpIn)
|
||||
{
|
||||
this.canJump = canJumpIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to actually make the entity jump if isJumping is true.
|
||||
*/
|
||||
public void doJump()
|
||||
{
|
||||
if (this.isJumping)
|
||||
{
|
||||
this.rabbit.startJumping();
|
||||
this.isJumping = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class RabbitMoveHelper extends EntityMoveHelper
|
||||
{
|
||||
private final EntityRabbit rabbit;
|
||||
private double nextJumpSpeed;
|
||||
|
||||
public RabbitMoveHelper(EntityRabbit rabbit)
|
||||
{
|
||||
super(rabbit);
|
||||
this.rabbit = rabbit;
|
||||
}
|
||||
|
||||
public void onUpdateMoveHelper()
|
||||
{
|
||||
if (this.rabbit.onGround && !this.rabbit.isJumping && !((EntityRabbit.RabbitJumpHelper)this.rabbit.jumpHelper).getIsJumping())
|
||||
{
|
||||
this.rabbit.setMovementSpeed(0.0D);
|
||||
}
|
||||
else if (this.isUpdating())
|
||||
{
|
||||
this.rabbit.setMovementSpeed(this.nextJumpSpeed);
|
||||
}
|
||||
|
||||
super.onUpdateMoveHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed and location to move to
|
||||
*/
|
||||
public void setMoveTo(double x, double y, double z, double speedIn)
|
||||
{
|
||||
if (this.rabbit.isInWater())
|
||||
{
|
||||
speedIn = 1.5D;
|
||||
}
|
||||
|
||||
super.setMoveTo(x, y, z, speedIn);
|
||||
|
||||
if (speedIn > 0.0D)
|
||||
{
|
||||
this.nextJumpSpeed = speedIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class RabbitTypeData implements IEntityLivingData
|
||||
{
|
||||
public int typeData;
|
||||
|
||||
public RabbitTypeData(int type)
|
||||
{
|
||||
this.typeData = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.IEntityLivingData;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIEatGrass;
|
||||
import net.minecraft.entity.ai.EntityAIFollowParent;
|
||||
import net.minecraft.entity.ai.EntityAILookIdle;
|
||||
import net.minecraft.entity.ai.EntityAIMate;
|
||||
import net.minecraft.entity.ai.EntityAIPanic;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITempt;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.InventoryCrafting;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
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.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntitySheep extends EntityAnimal implements net.minecraftforge.common.IShearable
|
||||
{
|
||||
private static final DataParameter<Byte> DYE_COLOR = EntityDataManager.<Byte>createKey(EntitySheep.class, DataSerializers.BYTE);
|
||||
/**
|
||||
* Internal crafting inventory used to check the result of mixing dyes corresponding to the fleece color when
|
||||
* breeding sheep.
|
||||
*/
|
||||
private final InventoryCrafting inventoryCrafting = new InventoryCrafting(new Container()
|
||||
{
|
||||
/**
|
||||
* Determines whether supplied player can use this container
|
||||
*/
|
||||
public boolean canInteractWith(EntityPlayer playerIn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}, 2, 1);
|
||||
/** Map from EnumDyeColor to RGB values for passage to GlStateManager.color() */
|
||||
private static final Map<EnumDyeColor, float[]> DYE_TO_RGB = Maps.newEnumMap(EnumDyeColor.class);
|
||||
/**
|
||||
* Used to control movement as well as wool regrowth. Set to 40 on handleHealthUpdate and counts down with each
|
||||
* tick.
|
||||
*/
|
||||
private int sheepTimer;
|
||||
private EntityAIEatGrass entityAIEatGrass;
|
||||
|
||||
private static float[] createSheepColor(EnumDyeColor p_192020_0_)
|
||||
{
|
||||
float[] afloat = p_192020_0_.getColorComponentValues();
|
||||
float f = 0.75F;
|
||||
return new float[] {afloat[0] * 0.75F, afloat[1] * 0.75F, afloat[2] * 0.75F};
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static float[] getDyeRgb(EnumDyeColor dyeColor)
|
||||
{
|
||||
return DYE_TO_RGB.get(dyeColor);
|
||||
}
|
||||
|
||||
public EntitySheep(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.9F, 1.3F);
|
||||
this.inventoryCrafting.setInventorySlotContents(0, new ItemStack(Items.DYE));
|
||||
this.inventoryCrafting.setInventorySlotContents(1, new ItemStack(Items.DYE));
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.entityAIEatGrass = new EntityAIEatGrass(this);
|
||||
this.tasks.addTask(0, new EntityAISwimming(this));
|
||||
this.tasks.addTask(1, new EntityAIPanic(this, 1.25D));
|
||||
this.tasks.addTask(2, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(3, new EntityAITempt(this, 1.1D, Items.WHEAT, false));
|
||||
this.tasks.addTask(4, new EntityAIFollowParent(this, 1.1D));
|
||||
this.tasks.addTask(5, this.entityAIEatGrass);
|
||||
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 1.0D));
|
||||
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(8, new EntityAILookIdle(this));
|
||||
}
|
||||
|
||||
protected void updateAITasks()
|
||||
{
|
||||
this.sheepTimer = this.entityAIEatGrass.getEatingGrassTimer();
|
||||
super.updateAITasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
this.sheepTimer = Math.max(0, this.sheepTimer - 1);
|
||||
}
|
||||
|
||||
super.onLivingUpdate();
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.23000000417232513D);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(DYE_COLOR, Byte.valueOf((byte)0));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
if (this.getSheared())
|
||||
{
|
||||
return LootTableList.ENTITIES_SHEEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (this.getFleeceColor())
|
||||
{
|
||||
case WHITE:
|
||||
default:
|
||||
return LootTableList.ENTITIES_SHEEP_WHITE;
|
||||
case ORANGE:
|
||||
return LootTableList.ENTITIES_SHEEP_ORANGE;
|
||||
case MAGENTA:
|
||||
return LootTableList.ENTITIES_SHEEP_MAGENTA;
|
||||
case LIGHT_BLUE:
|
||||
return LootTableList.ENTITIES_SHEEP_LIGHT_BLUE;
|
||||
case YELLOW:
|
||||
return LootTableList.ENTITIES_SHEEP_YELLOW;
|
||||
case LIME:
|
||||
return LootTableList.ENTITIES_SHEEP_LIME;
|
||||
case PINK:
|
||||
return LootTableList.ENTITIES_SHEEP_PINK;
|
||||
case GRAY:
|
||||
return LootTableList.ENTITIES_SHEEP_GRAY;
|
||||
case SILVER:
|
||||
return LootTableList.ENTITIES_SHEEP_SILVER;
|
||||
case CYAN:
|
||||
return LootTableList.ENTITIES_SHEEP_CYAN;
|
||||
case PURPLE:
|
||||
return LootTableList.ENTITIES_SHEEP_PURPLE;
|
||||
case BLUE:
|
||||
return LootTableList.ENTITIES_SHEEP_BLUE;
|
||||
case BROWN:
|
||||
return LootTableList.ENTITIES_SHEEP_BROWN;
|
||||
case GREEN:
|
||||
return LootTableList.ENTITIES_SHEEP_GREEN;
|
||||
case RED:
|
||||
return LootTableList.ENTITIES_SHEEP_RED;
|
||||
case BLACK:
|
||||
return LootTableList.ENTITIES_SHEEP_BLACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 10)
|
||||
{
|
||||
this.sheepTimer = 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (false && itemstack.getItem() == Items.SHEARS && !this.getSheared() && !this.isChild()) //Forge: Moved to onSheared
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.setSheared(true);
|
||||
int i = 1 + this.rand.nextInt(3);
|
||||
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
EntityItem entityitem = this.entityDropItem(new ItemStack(Item.getItemFromBlock(Blocks.WOOL), 1, this.getFleeceColor().getMetadata()), 1.0F);
|
||||
entityitem.motionY += (double)(this.rand.nextFloat() * 0.05F);
|
||||
entityitem.motionX += (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.1F);
|
||||
entityitem.motionZ += (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.1F);
|
||||
}
|
||||
}
|
||||
|
||||
itemstack.damageItem(1, player);
|
||||
this.playSound(SoundEvents.ENTITY_SHEEP_SHEAR, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
|
||||
public static void registerFixesSheep(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntitySheep.class);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getHeadRotationPointY(float p_70894_1_)
|
||||
{
|
||||
if (this.sheepTimer <= 0)
|
||||
{
|
||||
return 0.0F;
|
||||
}
|
||||
else if (this.sheepTimer >= 4 && this.sheepTimer <= 36)
|
||||
{
|
||||
return 1.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.sheepTimer < 4 ? ((float)this.sheepTimer - p_70894_1_) / 4.0F : -((float)(this.sheepTimer - 40) - p_70894_1_) / 4.0F;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getHeadRotationAngleX(float p_70890_1_)
|
||||
{
|
||||
if (this.sheepTimer > 4 && this.sheepTimer <= 36)
|
||||
{
|
||||
float f = ((float)(this.sheepTimer - 4) - p_70890_1_) / 32.0F;
|
||||
return ((float)Math.PI / 5F) + ((float)Math.PI * 7F / 100F) * MathHelper.sin(f * 28.7F);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.sheepTimer > 0 ? ((float)Math.PI / 5F) : this.rotationPitch * 0.017453292F;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("Sheared", this.getSheared());
|
||||
compound.setByte("Color", (byte)this.getFleeceColor().getMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setSheared(compound.getBoolean("Sheared"));
|
||||
this.setFleeceColor(EnumDyeColor.byMetadata(compound.getByte("Color")));
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_SHEEP_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_SHEEP_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_SHEEP_DEATH;
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_SHEEP_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wool color of this sheep.
|
||||
*/
|
||||
public EnumDyeColor getFleeceColor()
|
||||
{
|
||||
return EnumDyeColor.byMetadata(((Byte)this.dataManager.get(DYE_COLOR)).byteValue() & 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wool color of this sheep
|
||||
*/
|
||||
public void setFleeceColor(EnumDyeColor color)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(DYE_COLOR)).byteValue();
|
||||
this.dataManager.set(DYE_COLOR, Byte.valueOf((byte)(b0 & 240 | color.getMetadata() & 15)));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if a sheeps wool has been sheared
|
||||
*/
|
||||
public boolean getSheared()
|
||||
{
|
||||
return (((Byte)this.dataManager.get(DYE_COLOR)).byteValue() & 16) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* make a sheep sheared if set to true
|
||||
*/
|
||||
public void setSheared(boolean sheared)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(DYE_COLOR)).byteValue();
|
||||
|
||||
if (sheared)
|
||||
{
|
||||
this.dataManager.set(DYE_COLOR, Byte.valueOf((byte)(b0 | 16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(DYE_COLOR, Byte.valueOf((byte)(b0 & -17)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses a "vanilla" sheep color based on the provided random.
|
||||
*/
|
||||
public static EnumDyeColor getRandomSheepColor(Random random)
|
||||
{
|
||||
int i = random.nextInt(100);
|
||||
|
||||
if (i < 5)
|
||||
{
|
||||
return EnumDyeColor.BLACK;
|
||||
}
|
||||
else if (i < 10)
|
||||
{
|
||||
return EnumDyeColor.GRAY;
|
||||
}
|
||||
else if (i < 15)
|
||||
{
|
||||
return EnumDyeColor.SILVER;
|
||||
}
|
||||
else if (i < 18)
|
||||
{
|
||||
return EnumDyeColor.BROWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
return random.nextInt(500) == 0 ? EnumDyeColor.PINK : EnumDyeColor.WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
public EntitySheep createChild(EntityAgeable ageable)
|
||||
{
|
||||
EntitySheep entitysheep = (EntitySheep)ageable;
|
||||
EntitySheep entitysheep1 = new EntitySheep(this.world);
|
||||
entitysheep1.setFleeceColor(this.getDyeColorMixFromParents(this, entitysheep));
|
||||
return entitysheep1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
|
||||
* function is used in the AIEatGrass)
|
||||
*/
|
||||
public void eatGrassBonus()
|
||||
{
|
||||
this.setSheared(false);
|
||||
|
||||
if (this.isChild())
|
||||
{
|
||||
this.addGrowth(60);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
|
||||
* when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
|
||||
*/
|
||||
@Nullable
|
||||
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
|
||||
{
|
||||
livingdata = super.onInitialSpawn(difficulty, livingdata);
|
||||
this.setFleeceColor(getRandomSheepColor(this.world.rand));
|
||||
return livingdata;
|
||||
}
|
||||
|
||||
@Override public boolean isShearable(ItemStack item, net.minecraft.world.IBlockAccess world, BlockPos pos){ return !this.getSheared() && !this.isChild(); }
|
||||
@Override
|
||||
public java.util.List<ItemStack> onSheared(ItemStack item, net.minecraft.world.IBlockAccess world, BlockPos pos, int fortune)
|
||||
{
|
||||
this.setSheared(true);
|
||||
int i = 1 + this.rand.nextInt(3);
|
||||
|
||||
java.util.List<ItemStack> ret = new java.util.ArrayList<ItemStack>();
|
||||
for (int j = 0; j < i; ++j)
|
||||
ret.add(new ItemStack(Item.getItemFromBlock(Blocks.WOOL), 1, this.getFleeceColor().getMetadata()));
|
||||
|
||||
this.playSound(SoundEvents.ENTITY_SHEEP_SHEAR, 1.0F, 1.0F);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to mix both parent sheep to come up with a mixed dye color.
|
||||
*/
|
||||
private EnumDyeColor getDyeColorMixFromParents(EntityAnimal father, EntityAnimal mother)
|
||||
{
|
||||
int i = ((EntitySheep)father).getFleeceColor().getDyeDamage();
|
||||
int j = ((EntitySheep)mother).getFleeceColor().getDyeDamage();
|
||||
this.inventoryCrafting.getStackInSlot(0).setItemDamage(i);
|
||||
this.inventoryCrafting.getStackInSlot(1).setItemDamage(j);
|
||||
ItemStack itemstack = CraftingManager.findMatchingResult(this.inventoryCrafting, ((EntitySheep)father).world);
|
||||
int k;
|
||||
|
||||
if (itemstack.getItem() == Items.DYE)
|
||||
{
|
||||
k = itemstack.getMetadata();
|
||||
}
|
||||
else
|
||||
{
|
||||
k = this.world.rand.nextBoolean() ? i : j;
|
||||
}
|
||||
|
||||
return EnumDyeColor.byDyeDamage(k);
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return 0.95F * this.height;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
for (EnumDyeColor enumdyecolor : EnumDyeColor.values())
|
||||
{
|
||||
DYE_TO_RGB.put(enumdyecolor, createSheepColor(enumdyecolor));
|
||||
}
|
||||
|
||||
DYE_TO_RGB.put(EnumDyeColor.WHITE, new float[] {0.9019608F, 0.9019608F, 0.9019608F});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityShoulderRiding extends EntityTameable
|
||||
{
|
||||
private int rideCooldownCounter;
|
||||
|
||||
public EntityShoulderRiding(World p_i47410_1_)
|
||||
{
|
||||
super(p_i47410_1_);
|
||||
}
|
||||
|
||||
public boolean setEntityOnShoulder(EntityPlayer p_191994_1_)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
nbttagcompound.setString("id", this.getEntityString());
|
||||
this.writeToNBT(nbttagcompound);
|
||||
|
||||
if (p_191994_1_.addShoulderEntity(nbttagcompound))
|
||||
{
|
||||
this.world.removeEntity(this);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
++this.rideCooldownCounter;
|
||||
super.onUpdate();
|
||||
}
|
||||
|
||||
public boolean canSitOnShoulder()
|
||||
{
|
||||
return this.rideCooldownCounter > 100;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.EnumCreatureAttribute;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAISkeletonRiders;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntitySkeletonHorse extends AbstractHorse
|
||||
{
|
||||
private final EntityAISkeletonRiders skeletonTrapAI = new EntityAISkeletonRiders(this);
|
||||
private boolean skeletonTrap;
|
||||
private int skeletonTrapTime;
|
||||
|
||||
public EntitySkeletonHorse(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(15.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
|
||||
this.getEntityAttribute(JUMP_STRENGTH).setBaseValue(this.getModifiedJumpStrength());
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
super.getAmbientSound();
|
||||
return SoundEvents.ENTITY_SKELETON_HORSE_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
super.getDeathSound();
|
||||
return SoundEvents.ENTITY_SKELETON_HORSE_DEATH;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
super.getHurtSound(damageSourceIn);
|
||||
return SoundEvents.ENTITY_SKELETON_HORSE_HURT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this Entity's EnumCreatureAttribute
|
||||
*/
|
||||
public EnumCreatureAttribute getCreatureAttribute()
|
||||
{
|
||||
return EnumCreatureAttribute.UNDEAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Y offset from the entity's position for any entity riding this one.
|
||||
*/
|
||||
public double getMountedYOffset()
|
||||
{
|
||||
return super.getMountedYOffset() - 0.1875D;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_SKELETON_HORSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
|
||||
if (this.isTrap() && this.skeletonTrapTime++ >= 18000)
|
||||
{
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerFixesSkeletonHorse(DataFixer fixer)
|
||||
{
|
||||
AbstractHorse.registerFixesAbstractHorse(fixer, EntitySkeletonHorse.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("SkeletonTrap", this.isTrap());
|
||||
compound.setInteger("SkeletonTrapTime", this.skeletonTrapTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setTrap(compound.getBoolean("SkeletonTrap"));
|
||||
this.skeletonTrapTime = compound.getInteger("SkeletonTrapTime");
|
||||
}
|
||||
|
||||
public boolean isTrap()
|
||||
{
|
||||
return this.skeletonTrap;
|
||||
}
|
||||
|
||||
public void setTrap(boolean trap)
|
||||
{
|
||||
if (trap != this.skeletonTrap)
|
||||
{
|
||||
this.skeletonTrap = trap;
|
||||
|
||||
if (trap)
|
||||
{
|
||||
this.tasks.addTask(1, this.skeletonTrapAI);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tasks.removeTask(this.skeletonTrapAI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
boolean flag = !itemstack.isEmpty();
|
||||
|
||||
if (flag && itemstack.getItem() == Items.SPAWN_EGG)
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else if (!this.isTame())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.isChild())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else if (player.isSneaking())
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
else if (this.isBeingRidden())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
if (itemstack.getItem() == Items.SADDLE && !this.isHorseSaddled())
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemstack.interactWithEntity(player, this, hand))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.mountTo(player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIBase;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntitySquid extends EntityWaterMob
|
||||
{
|
||||
public float squidPitch;
|
||||
public float prevSquidPitch;
|
||||
public float squidYaw;
|
||||
public float prevSquidYaw;
|
||||
/** appears to be rotation in radians; we already have pitch & yaw, so this completes the triumvirate. */
|
||||
public float squidRotation;
|
||||
/** previous squidRotation in radians */
|
||||
public float prevSquidRotation;
|
||||
/** angle of the tentacles in radians */
|
||||
public float tentacleAngle;
|
||||
/** the last calculated angle of the tentacles in radians */
|
||||
public float lastTentacleAngle;
|
||||
private float randomMotionSpeed;
|
||||
/** change in squidRotation in radians. */
|
||||
private float rotationVelocity;
|
||||
private float rotateSpeed;
|
||||
private float randomMotionVecX;
|
||||
private float randomMotionVecY;
|
||||
private float randomMotionVecZ;
|
||||
|
||||
public EntitySquid(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.8F, 0.8F);
|
||||
this.rand.setSeed((long)(1 + this.getEntityId()));
|
||||
this.rotationVelocity = 1.0F / (this.rand.nextFloat() + 1.0F) * 0.2F;
|
||||
}
|
||||
|
||||
public static void registerFixesSquid(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntitySquid.class);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.tasks.addTask(0, new EntitySquid.AIMoveRandom(this));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0D);
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.height * 0.5F;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_SQUID_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_SQUID_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_SQUID_DEATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume for the sounds this mob makes.
|
||||
*/
|
||||
protected float getSoundVolume()
|
||||
{
|
||||
return 0.4F;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
|
||||
* prevent them from trampling crops
|
||||
*/
|
||||
protected boolean canTriggerWalking()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_SQUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
this.prevSquidPitch = this.squidPitch;
|
||||
this.prevSquidYaw = this.squidYaw;
|
||||
this.prevSquidRotation = this.squidRotation;
|
||||
this.lastTentacleAngle = this.tentacleAngle;
|
||||
this.squidRotation += this.rotationVelocity;
|
||||
|
||||
if ((double)this.squidRotation > (Math.PI * 2D))
|
||||
{
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
this.squidRotation = ((float)Math.PI * 2F);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.squidRotation = (float)((double)this.squidRotation - (Math.PI * 2D));
|
||||
|
||||
if (this.rand.nextInt(10) == 0)
|
||||
{
|
||||
this.rotationVelocity = 1.0F / (this.rand.nextFloat() + 1.0F) * 0.2F;
|
||||
}
|
||||
|
||||
this.world.setEntityState(this, (byte)19);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.inWater)
|
||||
{
|
||||
if (this.squidRotation < (float)Math.PI)
|
||||
{
|
||||
float f = this.squidRotation / (float)Math.PI;
|
||||
this.tentacleAngle = MathHelper.sin(f * f * (float)Math.PI) * (float)Math.PI * 0.25F;
|
||||
|
||||
if ((double)f > 0.75D)
|
||||
{
|
||||
this.randomMotionSpeed = 1.0F;
|
||||
this.rotateSpeed = 1.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.rotateSpeed *= 0.8F;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tentacleAngle = 0.0F;
|
||||
this.randomMotionSpeed *= 0.9F;
|
||||
this.rotateSpeed *= 0.99F;
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.motionX = (double)(this.randomMotionVecX * this.randomMotionSpeed);
|
||||
this.motionY = (double)(this.randomMotionVecY * this.randomMotionSpeed);
|
||||
this.motionZ = (double)(this.randomMotionVecZ * this.randomMotionSpeed);
|
||||
}
|
||||
|
||||
float f1 = MathHelper.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
|
||||
this.renderYawOffset += (-((float)MathHelper.atan2(this.motionX, this.motionZ)) * (180F / (float)Math.PI) - this.renderYawOffset) * 0.1F;
|
||||
this.rotationYaw = this.renderYawOffset;
|
||||
this.squidYaw = (float)((double)this.squidYaw + Math.PI * (double)this.rotateSpeed * 1.5D);
|
||||
this.squidPitch += (-((float)MathHelper.atan2((double)f1, this.motionY)) * (180F / (float)Math.PI) - this.squidPitch) * 0.1F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tentacleAngle = MathHelper.abs(MathHelper.sin(this.squidRotation)) * (float)Math.PI * 0.25F;
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.motionX = 0.0D;
|
||||
this.motionZ = 0.0D;
|
||||
|
||||
if (this.isPotionActive(MobEffects.LEVITATION))
|
||||
{
|
||||
this.motionY += 0.05D * (double)(this.getActivePotionEffect(MobEffects.LEVITATION).getAmplifier() + 1) - this.motionY;
|
||||
}
|
||||
else if (!this.hasNoGravity())
|
||||
{
|
||||
this.motionY -= 0.08D;
|
||||
}
|
||||
|
||||
this.motionY *= 0.9800000190734863D;
|
||||
}
|
||||
|
||||
this.squidPitch = (float)((double)this.squidPitch + (double)(-90.0F - this.squidPitch) * 0.02D);
|
||||
}
|
||||
}
|
||||
|
||||
public void travel(float strafe, float vertical, float forward)
|
||||
{
|
||||
this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
return this.posY > 45.0D && this.posY < (double)this.world.getSeaLevel() && super.getCanSpawnHere();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 19)
|
||||
{
|
||||
this.squidRotation = 0.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMovementVector(float randomMotionVecXIn, float randomMotionVecYIn, float randomMotionVecZIn)
|
||||
{
|
||||
this.randomMotionVecX = randomMotionVecXIn;
|
||||
this.randomMotionVecY = randomMotionVecYIn;
|
||||
this.randomMotionVecZ = randomMotionVecZIn;
|
||||
}
|
||||
|
||||
public boolean hasMovementVector()
|
||||
{
|
||||
return this.randomMotionVecX != 0.0F || this.randomMotionVecY != 0.0F || this.randomMotionVecZ != 0.0F;
|
||||
}
|
||||
|
||||
static class AIMoveRandom extends EntityAIBase
|
||||
{
|
||||
private final EntitySquid squid;
|
||||
|
||||
public AIMoveRandom(EntitySquid p_i45859_1_)
|
||||
{
|
||||
this.squid = p_i45859_1_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep ticking a continuous task that has already been started
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
int i = this.squid.getIdleTime();
|
||||
|
||||
if (i > 100)
|
||||
{
|
||||
this.squid.setMovementVector(0.0F, 0.0F, 0.0F);
|
||||
}
|
||||
else if (this.squid.getRNG().nextInt(50) == 0 || !this.squid.inWater || !this.squid.hasMovementVector())
|
||||
{
|
||||
float f = this.squid.getRNG().nextFloat() * ((float)Math.PI * 2F);
|
||||
float f1 = MathHelper.cos(f) * 0.2F;
|
||||
float f2 = -0.1F + this.squid.getRNG().nextFloat() * 0.2F;
|
||||
float f3 = MathHelper.sin(f) * 0.2F;
|
||||
this.squid.setMovementVector(f1, f2, f3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.advancements.CriteriaTriggers;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.IEntityOwnable;
|
||||
import net.minecraft.entity.ai.EntityAISit;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
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.scoreboard.Team;
|
||||
import net.minecraft.server.management.PreYggdrasilConverter;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public abstract class EntityTameable extends EntityAnimal implements IEntityOwnable
|
||||
{
|
||||
protected static final DataParameter<Byte> TAMED = EntityDataManager.<Byte>createKey(EntityTameable.class, DataSerializers.BYTE);
|
||||
protected static final DataParameter<Optional<UUID>> OWNER_UNIQUE_ID = EntityDataManager.<Optional<UUID>>createKey(EntityTameable.class, DataSerializers.OPTIONAL_UNIQUE_ID);
|
||||
protected EntityAISit aiSit;
|
||||
|
||||
public EntityTameable(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setupTamedAI();
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(TAMED, Byte.valueOf((byte)0));
|
||||
this.dataManager.register(OWNER_UNIQUE_ID, Optional.absent());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
|
||||
if (this.getOwnerId() == null)
|
||||
{
|
||||
compound.setString("OwnerUUID", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
compound.setString("OwnerUUID", this.getOwnerId().toString());
|
||||
}
|
||||
|
||||
compound.setBoolean("Sitting", this.isSitting());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
String s;
|
||||
|
||||
if (compound.hasKey("OwnerUUID", 8))
|
||||
{
|
||||
s = compound.getString("OwnerUUID");
|
||||
}
|
||||
else
|
||||
{
|
||||
String s1 = compound.getString("Owner");
|
||||
s = PreYggdrasilConverter.convertMobOwnerIfNeeded(this.getServer(), s1);
|
||||
}
|
||||
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
this.setOwnerId(UUID.fromString(s));
|
||||
this.setTamed(true);
|
||||
}
|
||||
catch (Throwable var4)
|
||||
{
|
||||
this.setTamed(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.aiSit != null)
|
||||
{
|
||||
this.aiSit.setSitting(compound.getBoolean("Sitting"));
|
||||
}
|
||||
|
||||
this.setSitting(compound.getBoolean("Sitting"));
|
||||
}
|
||||
|
||||
public boolean canBeLeashedTo(EntityPlayer player)
|
||||
{
|
||||
return !this.getLeashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the taming effect, will either be hearts or smoke depending on status
|
||||
*/
|
||||
protected void playTameEffect(boolean play)
|
||||
{
|
||||
EnumParticleTypes enumparticletypes = EnumParticleTypes.HEART;
|
||||
|
||||
if (!play)
|
||||
{
|
||||
enumparticletypes = EnumParticleTypes.SMOKE_NORMAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
double d0 = this.rand.nextGaussian() * 0.02D;
|
||||
double d1 = this.rand.nextGaussian() * 0.02D;
|
||||
double d2 = this.rand.nextGaussian() * 0.02D;
|
||||
this.world.spawnParticle(enumparticletypes, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, d0, d1, d2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 7)
|
||||
{
|
||||
this.playTameEffect(true);
|
||||
}
|
||||
else if (id == 6)
|
||||
{
|
||||
this.playTameEffect(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTamed()
|
||||
{
|
||||
return (((Byte)this.dataManager.get(TAMED)).byteValue() & 4) != 0;
|
||||
}
|
||||
|
||||
public void setTamed(boolean tamed)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(TAMED)).byteValue();
|
||||
|
||||
if (tamed)
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 | 4)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 & -5)));
|
||||
}
|
||||
|
||||
this.setupTamedAI();
|
||||
}
|
||||
|
||||
protected void setupTamedAI()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean isSitting()
|
||||
{
|
||||
return (((Byte)this.dataManager.get(TAMED)).byteValue() & 1) != 0;
|
||||
}
|
||||
|
||||
public void setSitting(boolean sitting)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(TAMED)).byteValue();
|
||||
|
||||
if (sitting)
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 | 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 & -2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getOwnerId()
|
||||
{
|
||||
return (UUID)((Optional)this.dataManager.get(OWNER_UNIQUE_ID)).orNull();
|
||||
}
|
||||
|
||||
public void setOwnerId(@Nullable UUID p_184754_1_)
|
||||
{
|
||||
this.dataManager.set(OWNER_UNIQUE_ID, Optional.fromNullable(p_184754_1_));
|
||||
}
|
||||
|
||||
public void setTamedBy(EntityPlayer player)
|
||||
{
|
||||
this.setTamed(true);
|
||||
this.setOwnerId(player.getUniqueID());
|
||||
|
||||
if (player instanceof EntityPlayerMP)
|
||||
{
|
||||
CriteriaTriggers.TAME_ANIMAL.trigger((EntityPlayerMP)player, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityLivingBase getOwner()
|
||||
{
|
||||
try
|
||||
{
|
||||
UUID uuid = this.getOwnerId();
|
||||
return uuid == null ? null : this.world.getPlayerEntityByUUID(uuid);
|
||||
}
|
||||
catch (IllegalArgumentException var2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOwner(EntityLivingBase entityIn)
|
||||
{
|
||||
return entityIn == this.getOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AITask responsible of the sit logic
|
||||
*/
|
||||
public EntityAISit getAISit()
|
||||
{
|
||||
return this.aiSit;
|
||||
}
|
||||
|
||||
public boolean shouldAttackEntity(EntityLivingBase target, EntityLivingBase owner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Team getTeam()
|
||||
{
|
||||
if (this.isTamed())
|
||||
{
|
||||
EntityLivingBase entitylivingbase = this.getOwner();
|
||||
|
||||
if (entitylivingbase != null)
|
||||
{
|
||||
return entitylivingbase.getTeam();
|
||||
}
|
||||
}
|
||||
|
||||
return super.getTeam();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this Entity is on the same team as the given Entity.
|
||||
*/
|
||||
public boolean isOnSameTeam(Entity entityIn)
|
||||
{
|
||||
if (this.isTamed())
|
||||
{
|
||||
EntityLivingBase entitylivingbase = this.getOwner();
|
||||
|
||||
if (entityIn == entitylivingbase)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entitylivingbase != null)
|
||||
{
|
||||
return entitylivingbase.isOnSameTeam(entityIn);
|
||||
}
|
||||
}
|
||||
|
||||
return super.isOnSameTeam(entityIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mob's health reaches 0.
|
||||
*/
|
||||
public void onDeath(DamageSource cause)
|
||||
{
|
||||
if (!this.world.isRemote && this.world.getGameRules().getBoolean("showDeathMessages") && this.getOwner() instanceof EntityPlayerMP)
|
||||
{
|
||||
this.getOwner().sendMessage(this.getCombatTracker().getDeathMessage());
|
||||
}
|
||||
|
||||
super.onDeath(cause);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,89 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityWaterMob extends EntityLiving implements IAnimals
|
||||
{
|
||||
public EntityWaterMob(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public boolean canBreatheUnderwater()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the entity is not colliding with any blocks / liquids
|
||||
*/
|
||||
public boolean isNotColliding()
|
||||
{
|
||||
return this.world.checkNoEntityCollision(this.getEntityBoundingBox(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks, at least during which the living entity will be silent.
|
||||
*/
|
||||
public int getTalkInterval()
|
||||
{
|
||||
return 120;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an entity can be despawned, used on idle far away entities
|
||||
*/
|
||||
protected boolean canDespawn()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the experience points the entity currently has.
|
||||
*/
|
||||
protected int getExperiencePoints(EntityPlayer player)
|
||||
{
|
||||
return 1 + this.world.rand.nextInt(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called every tick from main Entity class
|
||||
*/
|
||||
public void onEntityUpdate()
|
||||
{
|
||||
int i = this.getAir();
|
||||
super.onEntityUpdate();
|
||||
|
||||
if (this.isEntityAlive() && !this.isInWater())
|
||||
{
|
||||
--i;
|
||||
this.setAir(i);
|
||||
|
||||
if (this.getAir() == -20)
|
||||
{
|
||||
this.setAir(0);
|
||||
this.attackEntityFrom(DamageSource.DROWN, 2.0F);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setAir(300);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPushedByWater()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityAgeable;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.EntityAIAttackMelee;
|
||||
import net.minecraft.entity.ai.EntityAIAvoidEntity;
|
||||
import net.minecraft.entity.ai.EntityAIBeg;
|
||||
import net.minecraft.entity.ai.EntityAIFollowOwner;
|
||||
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.EntityAIOwnerHurtByTarget;
|
||||
import net.minecraft.entity.ai.EntityAIOwnerHurtTarget;
|
||||
import net.minecraft.entity.ai.EntityAISit;
|
||||
import net.minecraft.entity.ai.EntityAISwimming;
|
||||
import net.minecraft.entity.ai.EntityAITargetNonTamed;
|
||||
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||
import net.minecraft.entity.monster.AbstractSkeleton;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import net.minecraft.entity.monster.EntityGhast;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.projectile.EntityArrow;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.EnumDyeColor;
|
||||
import net.minecraft.item.ItemFood;
|
||||
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.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityWolf extends EntityTameable
|
||||
{
|
||||
private static final DataParameter<Float> DATA_HEALTH_ID = EntityDataManager.<Float>createKey(EntityWolf.class, DataSerializers.FLOAT);
|
||||
private static final DataParameter<Boolean> BEGGING = EntityDataManager.<Boolean>createKey(EntityWolf.class, DataSerializers.BOOLEAN);
|
||||
private static final DataParameter<Integer> COLLAR_COLOR = EntityDataManager.<Integer>createKey(EntityWolf.class, DataSerializers.VARINT);
|
||||
/** Float used to smooth the rotation of the wolf head */
|
||||
private float headRotationCourse;
|
||||
private float headRotationCourseOld;
|
||||
/** true is the wolf is wet else false */
|
||||
private boolean isWet;
|
||||
/** True if the wolf is shaking else False */
|
||||
private boolean isShaking;
|
||||
/** This time increases while wolf is shaking and emitting water particles. */
|
||||
private float timeWolfIsShaking;
|
||||
private float prevTimeWolfIsShaking;
|
||||
|
||||
public EntityWolf(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.6F, 0.85F);
|
||||
this.setTamed(false);
|
||||
}
|
||||
|
||||
protected void initEntityAI()
|
||||
{
|
||||
this.aiSit = new EntityAISit(this);
|
||||
this.tasks.addTask(1, new EntityAISwimming(this));
|
||||
this.tasks.addTask(2, this.aiSit);
|
||||
this.tasks.addTask(3, new EntityWolf.AIAvoidEntity(this, EntityLlama.class, 24.0F, 1.5D, 1.5D));
|
||||
this.tasks.addTask(4, new EntityAILeapAtTarget(this, 0.4F));
|
||||
this.tasks.addTask(5, new EntityAIAttackMelee(this, 1.0D, true));
|
||||
this.tasks.addTask(6, new EntityAIFollowOwner(this, 1.0D, 10.0F, 2.0F));
|
||||
this.tasks.addTask(7, new EntityAIMate(this, 1.0D));
|
||||
this.tasks.addTask(8, new EntityAIWanderAvoidWater(this, 1.0D));
|
||||
this.tasks.addTask(9, new EntityAIBeg(this, 8.0F));
|
||||
this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
|
||||
this.tasks.addTask(10, new EntityAILookIdle(this));
|
||||
this.targetTasks.addTask(1, new EntityAIOwnerHurtByTarget(this));
|
||||
this.targetTasks.addTask(2, new EntityAIOwnerHurtTarget(this));
|
||||
this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0]));
|
||||
this.targetTasks.addTask(4, new EntityAITargetNonTamed(this, EntityAnimal.class, false, new Predicate<Entity>()
|
||||
{
|
||||
public boolean apply(@Nullable Entity p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ instanceof EntitySheep || p_apply_1_ instanceof EntityRabbit;
|
||||
}
|
||||
}));
|
||||
this.targetTasks.addTask(5, new EntityAINearestAttackableTarget(this, AbstractSkeleton.class, false));
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896D);
|
||||
|
||||
if (this.isTamed())
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0D);
|
||||
}
|
||||
|
||||
this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(2.0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the active target the Task system uses for tracking
|
||||
*/
|
||||
public void setAttackTarget(@Nullable EntityLivingBase entitylivingbaseIn)
|
||||
{
|
||||
super.setAttackTarget(entitylivingbaseIn);
|
||||
|
||||
if (entitylivingbaseIn == null)
|
||||
{
|
||||
this.setAngry(false);
|
||||
}
|
||||
else if (!this.isTamed())
|
||||
{
|
||||
this.setAngry(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateAITasks()
|
||||
{
|
||||
this.dataManager.set(DATA_HEALTH_ID, Float.valueOf(this.getHealth()));
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(DATA_HEALTH_ID, Float.valueOf(this.getHealth()));
|
||||
this.dataManager.register(BEGGING, Boolean.valueOf(false));
|
||||
this.dataManager.register(COLLAR_COLOR, Integer.valueOf(EnumDyeColor.RED.getDyeDamage()));
|
||||
}
|
||||
|
||||
protected void playStepSound(BlockPos pos, Block blockIn)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_WOLF_STEP, 0.15F, 1.0F);
|
||||
}
|
||||
|
||||
public static void registerFixesWolf(DataFixer fixer)
|
||||
{
|
||||
EntityLiving.registerFixesMob(fixer, EntityWolf.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setBoolean("Angry", this.isAngry());
|
||||
compound.setByte("CollarColor", (byte)this.getCollarColor().getDyeDamage());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setAngry(compound.getBoolean("Angry"));
|
||||
|
||||
if (compound.hasKey("CollarColor", 99))
|
||||
{
|
||||
this.setCollarColor(EnumDyeColor.byDyeDamage(compound.getByte("CollarColor")));
|
||||
}
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
if (this.isAngry())
|
||||
{
|
||||
return SoundEvents.ENTITY_WOLF_GROWL;
|
||||
}
|
||||
else if (this.rand.nextInt(3) == 0)
|
||||
{
|
||||
return this.isTamed() && ((Float)this.dataManager.get(DATA_HEALTH_ID)).floatValue() < 10.0F ? SoundEvents.ENTITY_WOLF_WHINE : SoundEvents.ENTITY_WOLF_PANT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SoundEvents.ENTITY_WOLF_AMBIENT;
|
||||
}
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
return SoundEvents.ENTITY_WOLF_HURT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
return SoundEvents.ENTITY_WOLF_DEATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume for the sounds this mob makes.
|
||||
*/
|
||||
protected float getSoundVolume()
|
||||
{
|
||||
return 0.4F;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_WOLF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
|
||||
if (!this.world.isRemote && this.isWet && !this.isShaking && !this.hasPath() && this.onGround)
|
||||
{
|
||||
this.isShaking = true;
|
||||
this.timeWolfIsShaking = 0.0F;
|
||||
this.prevTimeWolfIsShaking = 0.0F;
|
||||
this.world.setEntityState(this, (byte)8);
|
||||
}
|
||||
|
||||
if (!this.world.isRemote && this.getAttackTarget() == null && this.isAngry())
|
||||
{
|
||||
this.setAngry(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
super.onUpdate();
|
||||
this.headRotationCourseOld = this.headRotationCourse;
|
||||
|
||||
if (this.isBegging())
|
||||
{
|
||||
this.headRotationCourse += (1.0F - this.headRotationCourse) * 0.4F;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.headRotationCourse += (0.0F - this.headRotationCourse) * 0.4F;
|
||||
}
|
||||
|
||||
if (this.isWet())
|
||||
{
|
||||
this.isWet = true;
|
||||
this.isShaking = false;
|
||||
this.timeWolfIsShaking = 0.0F;
|
||||
this.prevTimeWolfIsShaking = 0.0F;
|
||||
}
|
||||
else if ((this.isWet || this.isShaking) && this.isShaking)
|
||||
{
|
||||
if (this.timeWolfIsShaking == 0.0F)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_WOLF_SHAKE, this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
|
||||
}
|
||||
|
||||
this.prevTimeWolfIsShaking = this.timeWolfIsShaking;
|
||||
this.timeWolfIsShaking += 0.05F;
|
||||
|
||||
if (this.prevTimeWolfIsShaking >= 2.0F)
|
||||
{
|
||||
this.isWet = false;
|
||||
this.isShaking = false;
|
||||
this.prevTimeWolfIsShaking = 0.0F;
|
||||
this.timeWolfIsShaking = 0.0F;
|
||||
}
|
||||
|
||||
if (this.timeWolfIsShaking > 0.4F)
|
||||
{
|
||||
float f = (float)this.getEntityBoundingBox().minY;
|
||||
int i = (int)(MathHelper.sin((this.timeWolfIsShaking - 0.4F) * (float)Math.PI) * 7.0F);
|
||||
|
||||
for (int j = 0; j < i; ++j)
|
||||
{
|
||||
float f1 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width * 0.5F;
|
||||
float f2 = (this.rand.nextFloat() * 2.0F - 1.0F) * this.width * 0.5F;
|
||||
this.world.spawnParticle(EnumParticleTypes.WATER_SPLASH, this.posX + (double)f1, (double)(f + 0.8F), this.posZ + (double)f2, this.motionX, this.motionY, this.motionZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the wolf is wet
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isWolfWet()
|
||||
{
|
||||
return this.isWet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when calculating the amount of shading to apply while the wolf is wet.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getShadingWhileWet(float p_70915_1_)
|
||||
{
|
||||
return 0.75F + (this.prevTimeWolfIsShaking + (this.timeWolfIsShaking - this.prevTimeWolfIsShaking) * p_70915_1_) / 2.0F * 0.25F;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getShakeAngle(float p_70923_1_, float p_70923_2_)
|
||||
{
|
||||
float f = (this.prevTimeWolfIsShaking + (this.timeWolfIsShaking - this.prevTimeWolfIsShaking) * p_70923_1_ + p_70923_2_) / 1.8F;
|
||||
|
||||
if (f < 0.0F)
|
||||
{
|
||||
f = 0.0F;
|
||||
}
|
||||
else if (f > 1.0F)
|
||||
{
|
||||
f = 1.0F;
|
||||
}
|
||||
|
||||
return MathHelper.sin(f * (float)Math.PI) * MathHelper.sin(f * (float)Math.PI * 11.0F) * 0.15F * (float)Math.PI;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getInterestedAngle(float p_70917_1_)
|
||||
{
|
||||
return (this.headRotationCourseOld + (this.headRotationCourse - this.headRotationCourseOld) * p_70917_1_) * 0.15F * (float)Math.PI;
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return this.height * 0.8F;
|
||||
}
|
||||
|
||||
/**
|
||||
* The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently
|
||||
* use in wolves.
|
||||
*/
|
||||
public int getVerticalFaceSpeed()
|
||||
{
|
||||
return this.isSitting() ? 20 : super.getVerticalFaceSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity entity = source.getTrueSource();
|
||||
|
||||
if (this.aiSit != null)
|
||||
{
|
||||
this.aiSit.setSitting(false);
|
||||
}
|
||||
|
||||
if (entity != null && !(entity instanceof EntityPlayer) && !(entity instanceof EntityArrow))
|
||||
{
|
||||
amount = (amount + 1.0F) / 2.0F;
|
||||
}
|
||||
|
||||
return super.attackEntityFrom(source, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean attackEntityAsMob(Entity entityIn)
|
||||
{
|
||||
boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), (float)((int)this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue()));
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.applyEnchantments(this, entityIn);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void setTamed(boolean tamed)
|
||||
{
|
||||
super.setTamed(tamed);
|
||||
|
||||
if (tamed)
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(8.0D);
|
||||
}
|
||||
|
||||
this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(4.0D);
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (this.isTamed())
|
||||
{
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
if (itemstack.getItem() instanceof ItemFood)
|
||||
{
|
||||
ItemFood itemfood = (ItemFood)itemstack.getItem();
|
||||
|
||||
if (itemfood.isWolfsFavoriteMeat() && ((Float)this.dataManager.get(DATA_HEALTH_ID)).floatValue() < 20.0F)
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
this.heal((float)itemfood.getHealAmount(itemstack));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (itemstack.getItem() == Items.DYE)
|
||||
{
|
||||
EnumDyeColor enumdyecolor = EnumDyeColor.byDyeDamage(itemstack.getMetadata());
|
||||
|
||||
if (enumdyecolor != this.getCollarColor())
|
||||
{
|
||||
this.setCollarColor(enumdyecolor);
|
||||
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isOwner(player) && !this.world.isRemote && !this.isBreedingItem(itemstack))
|
||||
{
|
||||
this.aiSit.setSitting(!this.isSitting());
|
||||
this.isJumping = false;
|
||||
this.navigator.clearPath();
|
||||
this.setAttackTarget((EntityLivingBase)null);
|
||||
}
|
||||
}
|
||||
else if (itemstack.getItem() == Items.BONE && !this.isAngry())
|
||||
{
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
if (this.rand.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, player))
|
||||
{
|
||||
this.setTamedBy(player);
|
||||
this.navigator.clearPath();
|
||||
this.setAttackTarget((EntityLivingBase)null);
|
||||
this.aiSit.setSitting(true);
|
||||
this.setHealth(20.0F);
|
||||
this.playTameEffect(true);
|
||||
this.world.setEntityState(this, (byte)7);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.playTameEffect(false);
|
||||
this.world.setEntityState(this, (byte)6);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@link World#setEntityState}
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void handleStatusUpdate(byte id)
|
||||
{
|
||||
if (id == 8)
|
||||
{
|
||||
this.isShaking = true;
|
||||
this.timeWolfIsShaking = 0.0F;
|
||||
this.prevTimeWolfIsShaking = 0.0F;
|
||||
}
|
||||
else
|
||||
{
|
||||
super.handleStatusUpdate(id);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public float getTailRotation()
|
||||
{
|
||||
if (this.isAngry())
|
||||
{
|
||||
return 1.5393804F;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.isTamed() ? (0.55F - (this.getMaxHealth() - ((Float)this.dataManager.get(DATA_HEALTH_ID)).floatValue()) * 0.02F) * (float)Math.PI : ((float)Math.PI / 5F);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
public boolean isBreedingItem(ItemStack stack)
|
||||
{
|
||||
return stack.getItem() instanceof ItemFood && ((ItemFood)stack.getItem()).isWolfsFavoriteMeat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return how many at most can spawn in a chunk at once.
|
||||
*/
|
||||
public int getMaxSpawnedInChunk()
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this wolf is angry or not.
|
||||
*/
|
||||
public boolean isAngry()
|
||||
{
|
||||
return (((Byte)this.dataManager.get(TAMED)).byteValue() & 2) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this wolf is angry or not.
|
||||
*/
|
||||
public void setAngry(boolean angry)
|
||||
{
|
||||
byte b0 = ((Byte)this.dataManager.get(TAMED)).byteValue();
|
||||
|
||||
if (angry)
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 | 2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataManager.set(TAMED, Byte.valueOf((byte)(b0 & -3)));
|
||||
}
|
||||
}
|
||||
|
||||
public EnumDyeColor getCollarColor()
|
||||
{
|
||||
return EnumDyeColor.byDyeDamage(((Integer)this.dataManager.get(COLLAR_COLOR)).intValue() & 15);
|
||||
}
|
||||
|
||||
public void setCollarColor(EnumDyeColor collarcolor)
|
||||
{
|
||||
this.dataManager.set(COLLAR_COLOR, Integer.valueOf(collarcolor.getDyeDamage()));
|
||||
}
|
||||
|
||||
public EntityWolf createChild(EntityAgeable ageable)
|
||||
{
|
||||
EntityWolf entitywolf = new EntityWolf(this.world);
|
||||
UUID uuid = this.getOwnerId();
|
||||
|
||||
if (uuid != null)
|
||||
{
|
||||
entitywolf.setOwnerId(uuid);
|
||||
entitywolf.setTamed(true);
|
||||
}
|
||||
|
||||
return entitywolf;
|
||||
}
|
||||
|
||||
public void setBegging(boolean beg)
|
||||
{
|
||||
this.dataManager.set(BEGGING, Boolean.valueOf(beg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mob is currently able to mate with the specified mob.
|
||||
*/
|
||||
public boolean canMateWith(EntityAnimal otherAnimal)
|
||||
{
|
||||
if (otherAnimal == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!(otherAnimal instanceof EntityWolf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityWolf entitywolf = (EntityWolf)otherAnimal;
|
||||
|
||||
if (!entitywolf.isTamed())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (entitywolf.isSitting())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.isInLove() && entitywolf.isInLove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBegging()
|
||||
{
|
||||
return ((Boolean)this.dataManager.get(BEGGING)).booleanValue();
|
||||
}
|
||||
|
||||
public boolean shouldAttackEntity(EntityLivingBase target, EntityLivingBase owner)
|
||||
{
|
||||
if (!(target instanceof EntityCreeper) && !(target instanceof EntityGhast))
|
||||
{
|
||||
if (target instanceof EntityWolf)
|
||||
{
|
||||
EntityWolf entitywolf = (EntityWolf)target;
|
||||
|
||||
if (entitywolf.isTamed() && entitywolf.getOwner() == owner)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target instanceof EntityPlayer && owner instanceof EntityPlayer && !((EntityPlayer)owner).canAttackPlayer((EntityPlayer)target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !(target instanceof AbstractHorse) || !((AbstractHorse)target).isTame();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBeLeashedTo(EntityPlayer player)
|
||||
{
|
||||
return !this.isAngry() && super.canBeLeashedTo(player);
|
||||
}
|
||||
|
||||
class AIAvoidEntity<T extends Entity> extends EntityAIAvoidEntity<T>
|
||||
{
|
||||
private final EntityWolf wolf;
|
||||
|
||||
public AIAvoidEntity(EntityWolf wolfIn, Class<T> p_i47251_3_, float p_i47251_4_, double p_i47251_5_, double p_i47251_7_)
|
||||
{
|
||||
super(wolfIn, p_i47251_3_, p_i47251_4_, p_i47251_5_, p_i47251_7_);
|
||||
this.wolf = wolfIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the EntityAIBase should begin execution.
|
||||
*/
|
||||
public boolean shouldExecute()
|
||||
{
|
||||
if (super.shouldExecute() && this.closestLivingEntity instanceof EntityLlama)
|
||||
{
|
||||
return !this.wolf.isTamed() && this.avoidLlama((EntityLlama)this.closestLivingEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean avoidLlama(EntityLlama p_190854_1_)
|
||||
{
|
||||
return p_190854_1_.getStrength() >= EntityWolf.this.rand.nextInt(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a one shot task or start executing a continuous task
|
||||
*/
|
||||
public void startExecuting()
|
||||
{
|
||||
EntityWolf.this.setAttackTarget((EntityLivingBase)null);
|
||||
super.startExecuting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep ticking a continuous task that has already been started
|
||||
*/
|
||||
public void updateTask()
|
||||
{
|
||||
EntityWolf.this.setAttackTarget((EntityLivingBase)null);
|
||||
super.updateTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.EnumCreatureAttribute;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.storage.loot.LootTableList;
|
||||
|
||||
public class EntityZombieHorse extends AbstractHorse
|
||||
{
|
||||
public EntityZombieHorse(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public static void registerFixesZombieHorse(DataFixer fixer)
|
||||
{
|
||||
AbstractHorse.registerFixesAbstractHorse(fixer, EntityZombieHorse.class);
|
||||
}
|
||||
|
||||
protected void applyEntityAttributes()
|
||||
{
|
||||
super.applyEntityAttributes();
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(15.0D);
|
||||
this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
|
||||
this.getEntityAttribute(JUMP_STRENGTH).setBaseValue(this.getModifiedJumpStrength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this Entity's EnumCreatureAttribute
|
||||
*/
|
||||
public EnumCreatureAttribute getCreatureAttribute()
|
||||
{
|
||||
return EnumCreatureAttribute.UNDEAD;
|
||||
}
|
||||
|
||||
protected SoundEvent getAmbientSound()
|
||||
{
|
||||
super.getAmbientSound();
|
||||
return SoundEvents.ENTITY_ZOMBIE_HORSE_AMBIENT;
|
||||
}
|
||||
|
||||
protected SoundEvent getDeathSound()
|
||||
{
|
||||
super.getDeathSound();
|
||||
return SoundEvents.ENTITY_ZOMBIE_HORSE_DEATH;
|
||||
}
|
||||
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
|
||||
{
|
||||
super.getHurtSound(damageSourceIn);
|
||||
return SoundEvents.ENTITY_ZOMBIE_HORSE_HURT;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected ResourceLocation getLootTable()
|
||||
{
|
||||
return LootTableList.ENTITIES_ZOMBIE_HORSE;
|
||||
}
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
boolean flag = !itemstack.isEmpty();
|
||||
|
||||
if (flag && itemstack.getItem() == Items.SPAWN_EGG)
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else if (!this.isTame())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.isChild())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else if (player.isSneaking())
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
else if (this.isBeingRidden())
|
||||
{
|
||||
return super.processInteract(player, hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
if (!this.isHorseSaddled() && itemstack.getItem() == Items.SADDLE)
|
||||
{
|
||||
this.openGUI(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemstack.interactWithEntity(player, this, hand))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.mountTo(player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public enum HorseArmorType
|
||||
{
|
||||
NONE(0),
|
||||
IRON(5, "iron", "meo"),
|
||||
GOLD(7, "gold", "goo"),
|
||||
DIAMOND(11, "diamond", "dio");
|
||||
|
||||
private final String textureName;
|
||||
private final String hash;
|
||||
private final int protection;
|
||||
|
||||
private HorseArmorType(int armorStrengthIn)
|
||||
{
|
||||
this.protection = armorStrengthIn;
|
||||
this.textureName = null;
|
||||
this.hash = "";
|
||||
}
|
||||
|
||||
private HorseArmorType(int armorStrengthIn, String p_i46800_4_, String p_i46800_5_)
|
||||
{
|
||||
this.protection = armorStrengthIn;
|
||||
this.textureName = "textures/entity/horse/armor/horse_armor_" + p_i46800_4_ + ".png";
|
||||
this.hash = p_i46800_5_;
|
||||
}
|
||||
|
||||
public int getOrdinal()
|
||||
{
|
||||
return this.ordinal();
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getHash()
|
||||
{
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
public int getProtection()
|
||||
{
|
||||
return this.protection;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SideOnly(Side.CLIENT)
|
||||
public String getTextureName()
|
||||
{
|
||||
return this.textureName;
|
||||
}
|
||||
|
||||
@Deprecated /**Forge: Use getByName. Ordinals of mod-added enum constants are dependent on load order, unlike names.**/
|
||||
public static HorseArmorType getByOrdinal(int ordinal)
|
||||
{
|
||||
return values()[ordinal];
|
||||
}
|
||||
|
||||
public static HorseArmorType getByItemStack(ItemStack stack)
|
||||
{
|
||||
return stack.getItem().getHorseArmorType(stack);
|
||||
}
|
||||
|
||||
@Deprecated //Forge: Use getByItemStack
|
||||
public static HorseArmorType getByItem(Item itemIn)
|
||||
{
|
||||
if (itemIn == Items.IRON_HORSE_ARMOR)
|
||||
{
|
||||
return IRON;
|
||||
}
|
||||
else if (itemIn == Items.GOLDEN_HORSE_ARMOR)
|
||||
{
|
||||
return GOLD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return itemIn == Items.DIAMOND_HORSE_ARMOR ? DIAMOND : NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated //Forge: Use ItemStack sensitive overload
|
||||
public static boolean isHorseArmor(Item itemIn)
|
||||
{
|
||||
return getByItem(itemIn) != NONE;
|
||||
}
|
||||
|
||||
/* ======================================== FORGE START ======================================== */
|
||||
//Allows for textures located outside the vanilla horse armor folder
|
||||
private HorseArmorType(String defaultTextureLocation, int armorStrengthIn)
|
||||
{
|
||||
this.protection = armorStrengthIn;
|
||||
this.textureName = defaultTextureLocation;
|
||||
this.hash = "forge";
|
||||
}
|
||||
|
||||
public static HorseArmorType getByName(String name)
|
||||
{
|
||||
HorseArmorType type = HorseArmorType.valueOf(name);
|
||||
return type != null ? type : NONE;
|
||||
}
|
||||
|
||||
public static boolean isHorseArmor(ItemStack stack)
|
||||
{
|
||||
return getByItemStack(stack) != NONE;
|
||||
}
|
||||
/* ======================================== FORGE END ======================================== */
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
public interface IAnimals
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.entity.passive;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
Reference in New Issue
Block a user