    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.isWheat(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            this.fleeingTick = 60;
    179            this.entityToAttack = null;
    180            this.inLove = 0;
    181            return super.attackEntityFrom(par1DamageSource, par2);
    182        }
    183
    184        /**
    185         * Takes a coordinate in and returns a weight to determine how likely this creature will try to path to the block.
    186         * Args: x, y, z
    187         */
    188        public float getBlockPathWeight(int par1, int par2, int par3)
    189        {
    190            return this.worldObj.getBlockId(par1, par2 - 1, par3) == Block.grass.blockID ? 10.0F : this.worldObj.getLightBrightness(par1, par2, par3) - 0.5F;
    191        }
    192
    193        /**
    194         * (abstract) Protected helper method to write subclass entity data to NBT.
    195         */
    196        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    197        {
    198            super.writeEntityToNBT(par1NBTTagCompound);
    199            par1NBTTagCompound.setInteger("InLove", this.inLove);
    200        }
    201
    202        /**
    203         * (abstract) Protected helper method to read subclass entity data from NBT.
    204         */
    205        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    206        {
    207            super.readEntityFromNBT(par1NBTTagCompound);
    208            this.inLove = par1NBTTagCompound.getInteger("InLove");
    209        }
    210
    211        /**
    212         * Finds the closest player within 16 blocks to attack, or null if this Entity isn't interested in attacking
    213         * (Animals, Spiders at day, peaceful PigZombies).
    214         */
    215        protected Entity findPlayerToAttack()
    216        {
    217            if (this.fleeingTick > 0)
    218            {
    219                return null;
    220            }
    221            else
    222            {
    223                float var1 = 8.0F;
    224                List var2;
    225                Iterator var3;
    226                EntityAnimal var4;
    227
    228                if (this.inLove > 0)
    229                {
    230                    var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1));
    231                    var3 = var2.iterator();
    232
    233                    while (var3.hasNext())
    234                    {
    235                        var4 = (EntityAnimal)var3.next();
    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                    var3 = var2.iterator();
    247
    248                    while (var3.hasNext())
    249                    {
    250                        EntityPlayer var5 = (EntityPlayer)var3.next();
    251
    252                        if (var5.getCurrentEquippedItem() != null && this.isWheat(var5.getCurrentEquippedItem()))
    253                        {
    254                            return var5;
    255                        }
    256                    }
    257                }
    258                else if (this.getGrowingAge() > 0)
    259                {
    260                    var2 = this.worldObj.getEntitiesWithinAABB(this.getClass(), this.boundingBox.expand((double)var1, (double)var1, (double)var1));
    261                    var3 = var2.iterator();
    262
    263                    while (var3.hasNext())
    264                    {
    265                        var4 = (EntityAnimal)var3.next();
    266
    267                        if (var4 != this && var4.getGrowingAge() < 0)
    268                        {
    269                            return var4;
    270                        }
    271                    }
    272                }
    273
    274                return null;
    275            }
    276        }
    277
    278        /**
    279         * Checks if the entity's current position is a valid location to spawn this entity.
    280         */
    281        public boolean getCanSpawnHere()
    282        {
    283            int var1 = MathHelper.floor_double(this.posX);
    284            int var2 = MathHelper.floor_double(this.boundingBox.minY);
    285            int var3 = MathHelper.floor_double(this.posZ);
    286            return this.worldObj.getBlockId(var1, var2 - 1, var3) == Block.grass.blockID && this.worldObj.getFullBlockLightValue(var1, var2, var3) > 8 && super.getCanSpawnHere();
    287        }
    288
    289        /**
    290         * Get number of ticks, at least during which the living entity will be silent.
    291         */
    292        public int getTalkInterval()
    293        {
    294            return 120;
    295        }
    296
    297        /**
    298         * Determines if an entity can be despawned, used on idle far away entities
    299         */
    300        protected boolean canDespawn()
    301        {
    302            return false;
    303        }
    304
    305        /**
    306         * Get the experience points the entity currently has.
    307         */
    308        protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
    309        {
    310            return 1 + this.worldObj.rand.nextInt(3);
    311        }
    312
    313        /**
    314         * Checks if the parameter is an wheat item.
    315         */
    316        public boolean isWheat(ItemStack par1ItemStack)
    317        {
    318            return par1ItemStack.itemID == Item.wheat.shiftedIndex;
    319        }
    320
    321        /**
    322         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
    323         */
    324        public boolean interact(EntityPlayer par1EntityPlayer)
    325        {
    326            ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem();
    327
    328            if (var2 != null && this.isWheat(var2) && this.getGrowingAge() == 0)
    329            {
    330                if (!par1EntityPlayer.capabilities.isCreativeMode)
    331                {
    332                    --var2.stackSize;
    333
    334                    if (var2.stackSize <= 0)
    335                    {
    336                        par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null);
    337                    }
    338                }
    339
    340                this.inLove = 600;
    341                this.entityToAttack = null;
    342
    343                for (int var3 = 0; var3 < 7; ++var3)
    344                {
    345                    double var4 = this.rand.nextGaussian() * 0.02D;
    346                    double var6 = this.rand.nextGaussian() * 0.02D;
    347                    double var8 = this.rand.nextGaussian() * 0.02D;
    348                    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);
    349                }
    350
    351                return true;
    352            }
    353            else
    354            {
    355                return super.interact(par1EntityPlayer);
    356            }
    357        }
    358
    359        /**
    360         * Returns if the entity is currently in 'love mode'.
    361         */
    362        public boolean isInLove()
    363        {
    364            return this.inLove > 0;
    365        }
    366
    367        public void resetInLove()
    368        {
    369            this.inLove = 0;
    370        }
    371
    372        /**
    373         * Returns true if the mob is currently able to mate with the specified mob.
    374         */
    375        public boolean canMateWith(EntityAnimal par1EntityAnimal)
    376        {
    377            return par1EntityAnimal == this ? false : (par1EntityAnimal.getClass() != this.getClass() ? false : this.isInLove() && par1EntityAnimal.isInLove());
    378        }
    379    }