    001    package net.minecraft.entity.passive;
    002
    003    import java.util.List;
    004    import net.minecraft.block.Block;
    005    import net.minecraft.entity.Entity;
    006    import net.minecraft.entity.EntityAgeable;
    007    import net.minecraft.entity.player.EntityPlayer;
    008    import net.minecraft.item.Item;
    009    import net.minecraft.item.ItemStack;
    010    import net.minecraft.nbt.NBTTagCompound;
    011    import net.minecraft.util.DamageSource;
    012    import net.minecraft.util.MathHelper;
    013    import net.minecraft.world.World;
    014
    015    public abstract class EntityAnimal extends EntityAgeable implements IAnimals
    016    {
    017        public int inLove;
    018
    019        /**
    020         * This is representation of a counter for reproduction progress. (Note that this is different from the inLove which
    021         * represent being in Love-Mode)
    022         */
    023        private int breeding = 0;
    024
    025        public EntityAnimal(World par1World)
    026        {
    027            super(par1World);
    028        }
    029
    030        /**
    031         * main AI tick function, replaces updateEntityActionState
    032         */
    033        protected void updateAITick()
    034        {
    035            if (this.getGrowingAge() != 0)
    036            {
    037                this.inLove = 0;
    038            }
    039
    040            super.updateAITick();
    041        }
    042
    043        /**
    044         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
    045         * use this to react to sunlight and start to burn.
    046         */
    047        public void onLivingUpdate()
    048        {
    049            super.onLivingUpdate();
    050
    051            if (this.getGrowingAge() != 0)
    052            {
    053                this.inLove = 0;
    054            }
    055
    056            if (this.inLove > 0)
    057            {
    058                --this.inLove;
    059                String var1 = "heart";
    060
    061                if (this.inLove % 10 == 0)
    062                {
    063                    double var2 = this.rand.nextGaussian() * 0.02D;
    064                    double var4 = this.rand.nextGaussian() * 0.02D;
    065                    double var6 = this.rand.nextGaussian() * 0.02D;
    066                    this.worldObj.spawnParticle(var1, 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, var2, var4, var6);
    067                }
    068            }
    069            else
    070            {
    071                this.breeding = 0;
    072            }
    073        }
    074
    075        /**
    076         * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack.
    077         */
    078        protected void attackEntity(Entity par1Entity, float par2)
    079        {
    080            if (par1Entity instanceof EntityPlayer)
    081            {
    082                if (par2 < 3.0F)
    083                {
    084                    double var3 = par1Entity.posX - this.posX;
    085                    double var5 = par1Entity.posZ - this.posZ;
    086                    this.rotationYaw = (float)(Math.atan2(var5, var3) * 180.0D / Math.PI) - 90.0F;
    087                    this.hasAttacked = true;
    088                }
    089
    090                EntityPlayer var7 = (EntityPlayer)par1Entity;
    091
    092                if (var7.getCurrentEquippedItem() == null || !this.isBreedingItem(var7.getCurrentEquippedItem()))
    093                {
    094                    this.entityToAttack = null;
    095                }
    096            }
    097            else if (par1Entity instanceof EntityAnimal)
    098            {
    099                EntityAnimal var8 = (EntityAnimal)par1Entity;
    100
    101                if (this.getGrowingAge() > 0 && var8.getGrowingAge() < 0)
    102                {
    103                    if ((double)par2 < 2.5D)
    104                    {
    105                        this.hasAttacked = true;
    106                    }
    107                }
    108                else if (this.inLove > 0 && var8.inLove > 0)
    109                {
    110                    if (var8.entityToAttack == null)
    111                    {
    112                        var8.entityToAttack = this;
    113                    }
    114
    115                    if (var8.entityToAttack == this && (double)par2 < 3.5D)
    116                    {
    117                        ++var8.inLove;
    118                        ++this.inLove;
    119                        ++this.breeding;
    120
    121                        if (this.breeding % 4 == 0)
    122                        {
    123                            this.worldObj.spawnParticle("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, 0.0D, 0.0D, 0.0D);
    124                        }
    125
    126                        if (this.breeding == 60)
    127                        {
    128                            this.procreate((EntityAnimal)par1Entity);
    129                        }
    130                    }
    131                    else
    132                    {
    133                        this.breeding = 0;
    134                    }
    135                }
    136                else
    137                {
    138                    this.breeding = 0;
    139                    this.entityToAttack = null;
    140                }
    141            }
    142        }
    143
    144        /**
    145         * Creates a baby animal according to the animal type of the target at the actual position and spawns 'love'
    146         * particles.
    147         */
    148        private void procreate(EntityAnimal par1EntityAnimal)
    149        {
    150            EntityAgeable var2 = this.func_90011_a(par1EntityAnimal);
    151
    152            if (var2 != null)
    153            {
    154                this.setGrowingAge(6000);
    155                par1EntityAnimal.setGrowingAge(6000);
    156                this.inLove = 0;
    157                this.breeding = 0;
    158                this.entityToAttack = null;
    159                par1EntityAnimal.entityToAttack = null;
    160                par1EntityAnimal.breeding = 0;
    161                par1EntityAnimal.inLove = 0;
    162                var2.setGrowingAge(-24000);
    163                var2.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
    164
    165                for (int var3 = 0; var3 < 7; ++var3)
    166                {
    167                    double var4 = this.rand.nextGaussian() * 0.02D;
    168                    double var6 = this.rand.nextGaussian() * 0.02D;
    169                    double var8 = this.rand.nextGaussian() * 0.02D;
    170                    this.worldObj.spawnParticle("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, var4, var6, var8);
    171                }
    172
    173                this.worldObj.spawnEntityInWorld(var2);
    174            }
    175        }
    176
    177        /**
    178         * Called when the entity is attacked.
    179         */
    180        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    181        {
    182            if (this.func_85032_ar())
    183            {
    184                return false;
    185            }
    186            else
    187            {
    188                this.fleeingTick = 60;
    189                this.entityToAttack = null;
    190                this.inLove = 0;
    191                return super.attackEntityFrom(par1DamageSource, par2);
    192            }
    193        }
    194
    195        /**
    196         * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block.
    197         * Args: x, y, z
    198         */
    199        public float getBlockPathWeight(int par1, int par2, int par3)
    200        {
    201            return this.worldObj.getBlockId(par1, par2 - 1, par3) == Block.grass.blockID ? 10.0F : this.worldObj.getLightBrightness(par1, par2, par3) - 0.5F;
    202        }
    203
    204        /**
    205         * (abstract) Protected helper method to write subclass entity data to NBT.
    206         */
    207        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    208        {
    209            super.writeEntityToNBT(par1NBTTagCompound);
    210            par1NBTTagCompound.setInteger("InLove", this.inLove);
    211        }
    212
    213        /**
    214         * (abstract) Protected helper method to read subclass entity data from NBT.
    215         */
    216        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    217        {
    218            super.readEntityFromNBT(par1NBTTagCompound);
    219            this.inLove = par1NBTTagCompound.getInteger("InLove");
    220        }
    221
    222        /**
    223         * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking
    224         * (Animals, Spiders at day, peaceful PigZombies).
    225         */
    226        protected Entity findPlayerToAttack()
    227        {
    228            if (this.fleeingTick > 0)
    229            {
    230                return null;
    231            }
    232            else
    233            {
    234                float var1 = 8.0F;
    235                List var2;
    236                int var3;
    237                EntityAnimal var4;
    238
    239                if (this.inLove > 0)
    240                {
    241                    var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1));
    242
    243                    for (var3 = 0; var3 < var2.size(); ++var3)
    244                    {
    245                        var4 = (EntityAnimal)var2.get(var3);
    246
    247                        if (var4 != this && var4.inLove > 0)
    248                        {
    249                            return var4;
    250                        }
    251                    }
    252                }
    253                else if (this.getGrowingAge() == 0)
    254                {
    255                    var2 = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, this.boundingBox.expand((double)var1, (double)var1, (double)var1));
    256
    257                    for (var3 = 0; var3 < var2.size(); ++var3)
    258                    {
    259                        EntityPlayer var5 = (EntityPlayer)var2.get(var3);
    260
    261                        if (var5.getCurrentEquippedItem() != null && this.isBreedingItem(var5.getCurrentEquippedItem()))
    262                        {
    263                            return var5;
    264                        }
    265                    }
    266                }
    267                else if (this.getGrowingAge() > 0)
    268                {
    269                    var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1));
    270
    271                    for (var3 = 0; var3 < var2.size(); ++var3)
    272                    {
    273                        var4 = (EntityAnimal)var2.get(var3);
    274
    275                        if (var4 != this && var4.getGrowingAge() < 0)
    276                        {
    277                            return var4;
    278                        }
    279                    }
    280                }
    281
    282                return null;
    283            }
    284        }
    285
    286        /**
    287         * Checks if the entity's current position is a valid location to spawn this entity.
    288         */
    289        public boolean getCanSpawnHere()
    290        {
    291            int var1 = MathHelper.floor_double(this.posX);
    292            int var2 = MathHelper.floor_double(this.boundingBox.minY);
    293            int var3 = MathHelper.floor_double(this.posZ);
    294            return this.worldObj.getBlockId(var1, var2 - 1, var3) == Block.grass.blockID && this.worldObj.getFullBlockLightValue(var1, var2, var3) > 8 && super.getCanSpawnHere();
    295        }
    296
    297        /**
    298         * Get number of ticks, at least during which the living entity will be silent.
    299         */
    300        public int getTalkInterval()
    301        {
    302            return 120;
    303        }
    304
    305        /**
    306         * Determines if an entity can be despawned, used on idle far away entities
    307         */
    308        protected boolean canDespawn()
    309        {
    310            return false;
    311        }
    312
    313        /**
    314         * Get the experience points the entity currently has.
    315         */
    316        protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
    317        {
    318            return 1 + this.worldObj.rand.nextInt(3);
    319        }
    320
    321        /**
    322         * Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on
    323         * the animal type)
    324         */
    325        public boolean isBreedingItem(ItemStack par1ItemStack)
    326        {
    327            return par1ItemStack.itemID == Item.wheat.shiftedIndex;
    328        }
    329
    330        /**
    331         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
    332         */
    333        public boolean interact(EntityPlayer par1EntityPlayer)
    334        {
    335            ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem();
    336
    337            if (var2 != null && this.isBreedingItem(var2) && this.getGrowingAge() == 0)
    338            {
    339                if (!par1EntityPlayer.capabilities.isCreativeMode)
    340                {
    341                    --var2.stackSize;
    342
    343                    if (var2.stackSize <= 0)
    344                    {
    345                        par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null);
    346                    }
    347                }
    348
    349                this.inLove = 600;
    350                this.entityToAttack = null;
    351
    352                for (int var3 = 0; var3 < 7; ++var3)
    353                {
    354                    double var4 = this.rand.nextGaussian() * 0.02D;
    355                    double var6 = this.rand.nextGaussian() * 0.02D;
    356                    double var8 = this.rand.nextGaussian() * 0.02D;
    357                    this.worldObj.spawnParticle("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, var4, var6, var8);
    358                }
    359
    360                return true;
    361            }
    362            else
    363            {
    364                return super.interact(par1EntityPlayer);
    365            }
    366        }
    367
    368        /**
    369         * Returns if the entity is currently in 'love mode'.
    370         */
    371        public boolean isInLove()
    372        {
    373            return this.inLove > 0;
    374        }
    375
    376        public void resetInLove()
    377        {
    378            this.inLove = 0;
    379        }
    380
    381        /**
    382         * Returns true if the mob is currently able to mate with the specified mob.
    383         */
    384        public boolean canMateWith(EntityAnimal par1EntityAnimal)
    385        {
    386            return par1EntityAnimal == this ? false : (par1EntityAnimal.getClass() != this.getClass() ? false : this.isInLove() && par1EntityAnimal.isInLove());
    387        }
    388    }