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