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