    001    package net.minecraft.src;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import java.util.Calendar;
    006    import java.util.Date;
    007
    008    public class EntityZombie extends EntityMob
    009    {
    010        private int field_82234_d = 0;
    011
    012        public EntityZombie(World par1World)
    013        {
    014            super(par1World);
    015            this.texture = "/mob/zombie.png";
    016            this.moveSpeed = 0.23F;
    017            this.getNavigator().setBreakDoors(true);
    018            this.tasks.addTask(0, new EntityAISwimming(this));
    019            this.tasks.addTask(1, new EntityAIBreakDoor(this));
    020            this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
    021            this.tasks.addTask(3, new EntityAIAttackOnCollide(this, EntityVillager.class, this.moveSpeed, true));
    022            this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, this.moveSpeed));
    023            this.tasks.addTask(5, new EntityAIMoveThroughVillage(this, this.moveSpeed, false));
    024            this.tasks.addTask(6, new EntityAIWander(this, this.moveSpeed));
    025            this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
    026            this.tasks.addTask(7, new EntityAILookIdle(this));
    027            this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
    028            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 16.0F, 0, true));
    029            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityVillager.class, 16.0F, 0, false));
    030        }
    031
    032        /**
    033         * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
    034         * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
    035         */
    036        public float getSpeedModifier()
    037        {
    038            return super.getSpeedModifier() * (this.isChild() ? 1.5F : 1.0F);
    039        }
    040
    041        protected void entityInit()
    042        {
    043            super.entityInit();
    044            this.getDataWatcher().addObject(12, Byte.valueOf((byte)0));
    045            this.getDataWatcher().addObject(13, Byte.valueOf((byte)0));
    046            this.getDataWatcher().addObject(14, Byte.valueOf((byte)0));
    047        }
    048
    049        @SideOnly(Side.CLIENT)
    050
    051        /**
    052         * Returns the texture's file path as a String.
    053         */
    054        public String getTexture()
    055        {
    056            return this.func_82231_m() ? "/mob/zombie_villager.png" : "/mob/zombie.png";
    057        }
    058
    059        public int getMaxHealth()
    060        {
    061            return 20;
    062        }
    063
    064        /**
    065         * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
    066         */
    067        public int getTotalArmorValue()
    068        {
    069            int var1 = super.getTotalArmorValue() + 2;
    070
    071            if (var1 > 20)
    072            {
    073                var1 = 20;
    074            }
    075
    076            return var1;
    077        }
    078
    079        /**
    080         * Returns true if the newer Entity AI code should be run
    081         */
    082        protected boolean isAIEnabled()
    083        {
    084            return true;
    085        }
    086
    087        /**
    088         * If Animal, checks if the age timer is negative
    089         */
    090        public boolean isChild()
    091        {
    092            return this.getDataWatcher().getWatchableObjectByte(12) == 1;
    093        }
    094
    095        public void func_82227_f(boolean par1)
    096        {
    097            this.getDataWatcher().updateObject(12, Byte.valueOf((byte)1));
    098        }
    099
    100        public boolean func_82231_m()
    101        {
    102            return this.getDataWatcher().getWatchableObjectByte(13) == 1;
    103        }
    104
    105        public void func_82229_g(boolean par1)
    106        {
    107            this.getDataWatcher().updateObject(13, Byte.valueOf((byte)(par1 ? 1 : 0)));
    108        }
    109
    110        /**
    111         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
    112         * use this to react to sunlight and start to burn.
    113         */
    114        public void onLivingUpdate()
    115        {
    116            if (this.worldObj.isDaytime() && !this.worldObj.isRemote && !this.isChild())
    117            {
    118                float var1 = this.getBrightness(1.0F);
    119
    120                if (var1 > 0.5F && this.rand.nextFloat() * 30.0F < (var1 - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)))
    121                {
    122                    boolean var2 = true;
    123                    ItemStack var3 = this.getCurrentItemOrArmor(4);
    124
    125                    if (var3 != null)
    126                    {
    127                        if (var3.isItemStackDamageable())
    128                        {
    129                            var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2));
    130
    131                            if (var3.getItemDamageForDisplay() >= var3.getMaxDamage())
    132                            {
    133                                this.renderBrokenItemStack(var3);
    134                                this.func_70062_b(4, (ItemStack)null);
    135                            }
    136                        }
    137
    138                        var2 = false;
    139                    }
    140
    141                    if (var2)
    142                    {
    143                        this.setFire(8);
    144                    }
    145                }
    146            }
    147
    148            super.onLivingUpdate();
    149        }
    150
    151        /**
    152         * Called to update the entity's position/logic.
    153         */
    154        public void onUpdate()
    155        {
    156            if (!this.worldObj.isRemote && this.func_82230_o())
    157            {
    158                int var1 = this.func_82233_q();
    159                this.field_82234_d -= var1;
    160
    161                if (this.field_82234_d <= 0)
    162                {
    163                    this.func_82232_p();
    164                }
    165            }
    166
    167            super.onUpdate();
    168        }
    169
    170        public int func_82193_c(Entity par1Entity)
    171        {
    172            ItemStack var2 = this.getHeldItem();
    173            int var3 = 4;
    174
    175            if (var2 != null)
    176            {
    177                var3 += var2.getDamageVsEntity(this);
    178            }
    179
    180            return var3;
    181        }
    182
    183        /**
    184         * Returns the sound this mob makes while it's alive.
    185         */
    186        protected String getLivingSound()
    187        {
    188            return "mob.zombie.say";
    189        }
    190
    191        /**
    192         * Returns the sound this mob makes when it is hurt.
    193         */
    194        protected String getHurtSound()
    195        {
    196            return "mob.zombie.hurt";
    197        }
    198
    199        /**
    200         * Returns the sound this mob makes on death.
    201         */
    202        protected String getDeathSound()
    203        {
    204            return "mob.zombie.death";
    205        }
    206
    207        /**
    208         * Plays step sound at given x, y, z for the entity
    209         */
    210        protected void playStepSound(int par1, int par2, int par3, int par4)
    211        {
    212            this.worldObj.playSoundAtEntity(this, "mob.zombie.step", 0.15F, 1.0F);
    213        }
    214
    215        /**
    216         * Returns the item ID for the item the mob drops on death.
    217         */
    218        protected int getDropItemId()
    219        {
    220            return Item.rottenFlesh.shiftedIndex;
    221        }
    222
    223        /**
    224         * Get this Entity's EnumCreatureAttribute
    225         */
    226        public EnumCreatureAttribute getCreatureAttribute()
    227        {
    228            return EnumCreatureAttribute.UNDEAD;
    229        }
    230
    231        protected void dropRareDrop(int par1)
    232        {
    233            switch (this.rand.nextInt(3))
    234            {
    235                case 0:
    236                    this.dropItem(Item.ingotIron.shiftedIndex, 1);
    237                    break;
    238                case 1:
    239                    this.dropItem(Item.field_82797_bK.shiftedIndex, 1);
    240                    break;
    241                case 2:
    242                    this.dropItem(Item.field_82794_bL.shiftedIndex, 1);
    243            }
    244        }
    245
    246        protected void func_82164_bB()
    247        {
    248            super.func_82164_bB();
    249
    250            if (this.rand.nextFloat() < (this.worldObj.difficultySetting == 3 ? 0.05F : 0.01F))
    251            {
    252                int var1 = this.rand.nextInt(3);
    253
    254                if (var1 == 0)
    255                {
    256                    this.func_70062_b(0, new ItemStack(Item.swordSteel));
    257                }
    258                else
    259                {
    260                    this.func_70062_b(0, new ItemStack(Item.shovelSteel));
    261                }
    262            }
    263        }
    264
    265        /**
    266         * (abstract) Protected helper method to write subclass entity data to NBT.
    267         */
    268        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    269        {
    270            super.writeEntityToNBT(par1NBTTagCompound);
    271
    272            if (this.isChild())
    273            {
    274                par1NBTTagCompound.setBoolean("IsBaby", true);
    275            }
    276
    277            if (this.func_82231_m())
    278            {
    279                par1NBTTagCompound.setBoolean("IsVillager", true);
    280            }
    281
    282            par1NBTTagCompound.setInteger("ConversionTime", this.func_82230_o() ? this.field_82234_d : -1);
    283        }
    284
    285        /**
    286         * (abstract) Protected helper method to read subclass entity data from NBT.
    287         */
    288        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    289        {
    290            super.readEntityFromNBT(par1NBTTagCompound);
    291
    292            if (par1NBTTagCompound.getBoolean("IsBaby"))
    293            {
    294                this.func_82227_f(true);
    295            }
    296
    297            if (par1NBTTagCompound.getBoolean("IsVillager"))
    298            {
    299                this.func_82229_g(true);
    300            }
    301
    302            if (par1NBTTagCompound.hasKey("ConversionTime") && par1NBTTagCompound.getInteger("ConversionTime") > -1)
    303            {
    304                this.func_82228_a(par1NBTTagCompound.getInteger("ConversionTime"));
    305            }
    306        }
    307
    308        /**
    309         * This method gets called when the entity kills another one.
    310         */
    311        public void onKillEntity(EntityLiving par1EntityLiving)
    312        {
    313            super.onKillEntity(par1EntityLiving);
    314
    315            if (this.worldObj.difficultySetting >= 2 && par1EntityLiving instanceof EntityVillager)
    316            {
    317                if (this.worldObj.difficultySetting == 2 && this.rand.nextBoolean())
    318                {
    319                    return;
    320                }
    321
    322                EntityZombie var2 = new EntityZombie(this.worldObj);
    323                var2.func_82149_j(par1EntityLiving);
    324                this.worldObj.setEntityDead(par1EntityLiving);
    325                var2.func_82163_bD();
    326                var2.func_82229_g(true);
    327
    328                if (par1EntityLiving.isChild())
    329                {
    330                    var2.func_82227_f(true);
    331                }
    332
    333                this.worldObj.spawnEntityInWorld(var2);
    334                this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1016, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    335            }
    336        }
    337
    338        public void func_82163_bD()
    339        {
    340            this.field_82172_bs = this.rand.nextFloat() < field_82181_as[this.worldObj.difficultySetting];
    341
    342            if (this.worldObj.rand.nextFloat() < 0.05F)
    343            {
    344                this.func_82229_g(true);
    345            }
    346
    347            this.func_82164_bB();
    348            this.func_82162_bC();
    349
    350            if (this.getCurrentItemOrArmor(4) == null)
    351            {
    352                Calendar var1 = Calendar.getInstance();
    353                var1.setTime(new Date());
    354
    355                if (var1.get(2) + 1 == 10 && var1.get(5) == 31 && this.rand.nextFloat() < 0.25F)
    356                {
    357                    this.func_70062_b(4, new ItemStack(this.rand.nextFloat() < 0.1F ? Block.pumpkinLantern : Block.pumpkin));
    358                    this.field_82174_bp[4] = 0.0F;
    359                }
    360            }
    361        }
    362
    363        /**
    364         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
    365         */
    366        public boolean interact(EntityPlayer par1EntityPlayer)
    367        {
    368            ItemStack var2 = par1EntityPlayer.getCurrentEquippedItem();
    369
    370            if (var2 != null && var2.getItem() == Item.appleGold && var2.getItemDamage() == 0 && this.func_82231_m() && this.isPotionActive(Potion.weakness))
    371            {
    372                if (!par1EntityPlayer.capabilities.isCreativeMode)
    373                {
    374                    --var2.stackSize;
    375                }
    376
    377                if (var2.stackSize <= 0)
    378                {
    379                    par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null);
    380                }
    381
    382                if (!this.worldObj.isRemote)
    383                {
    384                    this.func_82228_a(this.rand.nextInt(2401) + 3600);
    385                }
    386
    387                return true;
    388            }
    389            else
    390            {
    391                return false;
    392            }
    393        }
    394
    395        protected void func_82228_a(int par1)
    396        {
    397            this.field_82234_d = par1;
    398            this.getDataWatcher().updateObject(14, Byte.valueOf((byte)1));
    399            this.func_82170_o(Potion.weakness.id);
    400            this.addPotionEffect(new PotionEffect(Potion.damageBoost.id, par1, Math.min(this.worldObj.difficultySetting - 1, 0)));
    401            this.worldObj.setEntityState(this, (byte)16);
    402        }
    403
    404        @SideOnly(Side.CLIENT)
    405        public void handleHealthUpdate(byte par1)
    406        {
    407            if (par1 == 16)
    408            {
    409                this.worldObj.playSound(this.posX + 0.5D, this.posY + 0.5D, this.posZ + 0.5D, "mob.zombie.remedy", 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F);
    410            }
    411            else
    412            {
    413                super.handleHealthUpdate(par1);
    414            }
    415        }
    416
    417        public boolean func_82230_o()
    418        {
    419            return this.getDataWatcher().getWatchableObjectByte(14) == 1;
    420        }
    421
    422        protected void func_82232_p()
    423        {
    424            EntityVillager var1 = new EntityVillager(this.worldObj);
    425            var1.func_82149_j(this);
    426            var1.func_82163_bD();
    427            var1.func_82187_q();
    428
    429            if (this.isChild())
    430            {
    431                var1.setGrowingAge(-24000);
    432            }
    433
    434            this.worldObj.setEntityDead(this);
    435            this.worldObj.spawnEntityInWorld(var1);
    436            var1.addPotionEffect(new PotionEffect(Potion.confusion.id, 200, 0));
    437            this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1017, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    438        }
    439
    440        protected int func_82233_q()
    441        {
    442            int var1 = 1;
    443
    444            if (this.rand.nextFloat() < 0.01F)
    445            {
    446                int var2 = 0;
    447
    448                for (int var3 = (int)this.posX - 4; var3 < (int)this.posX + 4 && var2 < 14; ++var3)
    449                {
    450                    for (int var4 = (int)this.posY - 4; var4 < (int)this.posY + 4 && var2 < 14; ++var4)
    451                    {
    452                        for (int var5 = (int)this.posZ - 4; var5 < (int)this.posZ + 4 && var2 < 14; ++var5)
    453                        {
    454                            int var6 = this.worldObj.getBlockId(var3, var4, var5);
    455
    456                            if (var6 == Block.fenceIron.blockID || var6 == Block.bed.blockID)
    457                            {
    458                                if (this.rand.nextFloat() < 0.3F)
    459                                {
    460                                    ++var1;
    461                                }
    462
    463                                ++var2;
    464                            }
    465                        }
    466                    }
    467                }
    468            }
    469
    470            return var1;
    471        }
    472    }