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