    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 EntitySkeleton extends EntityMob implements IRangedAttackMob
    008    {
    009        public EntitySkeleton(World par1World)
    010        {
    011            super(par1World);
    012            this.texture = "/mob/skeleton.png";
    013            this.moveSpeed = 0.25F;
    014            this.tasks.addTask(1, new EntityAISwimming(this));
    015            this.tasks.addTask(2, new EntityAIRestrictSun(this));
    016            this.tasks.addTask(3, new EntityAIFleeSun(this, this.moveSpeed));
    017            this.tasks.addTask(5, new EntityAIWander(this, this.moveSpeed));
    018            this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
    019            this.tasks.addTask(6, new EntityAILookIdle(this));
    020            this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
    021            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 16.0F, 0, true));
    022        }
    023
    024        protected void entityInit()
    025        {
    026            super.entityInit();
    027            this.dataWatcher.addObject(13, new Byte((byte)0));
    028        }
    029
    030        /**
    031         * Returns true if the newer Entity AI code should be run
    032         */
    033        public boolean isAIEnabled()
    034        {
    035            return true;
    036        }
    037
    038        public int getMaxHealth()
    039        {
    040            return 20;
    041        }
    042
    043        /**
    044         * Returns the sound this mob makes while it's alive.
    045         */
    046        protected String getLivingSound()
    047        {
    048            return "mob.skeleton.say";
    049        }
    050
    051        /**
    052         * Returns the sound this mob makes when it is hurt.
    053         */
    054        protected String getHurtSound()
    055        {
    056            return "mob.skeleton.hurt";
    057        }
    058
    059        /**
    060         * Returns the sound this mob makes on death.
    061         */
    062        protected String getDeathSound()
    063        {
    064            return "mob.skeleton.death";
    065        }
    066
    067        /**
    068         * Plays step sound at given x, y, z for the entity
    069         */
    070        protected void playStepSound(int par1, int par2, int par3, int par4)
    071        {
    072            this.worldObj.playSoundAtEntity(this, "mob.skeleton.step", 0.15F, 1.0F);
    073        }
    074
    075        public boolean attackEntityAsMob(Entity par1Entity)
    076        {
    077            if (super.attackEntityAsMob(par1Entity))
    078            {
    079                if (this.func_82202_m() == 1 && par1Entity instanceof EntityLiving)
    080                {
    081                    ((EntityLiving)par1Entity).addPotionEffect(new PotionEffect(Potion.field_82731_v.id, 200));
    082                }
    083
    084                return true;
    085            }
    086            else
    087            {
    088                return false;
    089            }
    090        }
    091
    092        public int func_82193_c(Entity par1Entity)
    093        {
    094            if (this.func_82202_m() == 1)
    095            {
    096                ItemStack var2 = this.getHeldItem();
    097                int var3 = 4;
    098
    099                if (var2 != null)
    100                {
    101                    var3 += var2.getDamageVsEntity(this);
    102                }
    103
    104                return var3;
    105            }
    106            else
    107            {
    108                return super.func_82193_c(par1Entity);
    109            }
    110        }
    111
    112        /**
    113         * Get this Entity's EnumCreatureAttribute
    114         */
    115        public EnumCreatureAttribute getCreatureAttribute()
    116        {
    117            return EnumCreatureAttribute.UNDEAD;
    118        }
    119
    120        /**
    121         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
    122         * use this to react to sunlight and start to burn.
    123         */
    124        public void onLivingUpdate()
    125        {
    126            if (this.worldObj.isDaytime() && !this.worldObj.isRemote)
    127            {
    128                float var1 = this.getBrightness(1.0F);
    129
    130                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)))
    131                {
    132                    boolean var2 = true;
    133                    ItemStack var3 = this.getCurrentItemOrArmor(4);
    134
    135                    if (var3 != null)
    136                    {
    137                        if (var3.isItemStackDamageable())
    138                        {
    139                            var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2));
    140
    141                            if (var3.getItemDamageForDisplay() >= var3.getMaxDamage())
    142                            {
    143                                this.renderBrokenItemStack(var3);
    144                                this.func_70062_b(4, (ItemStack)null);
    145                            }
    146                        }
    147
    148                        var2 = false;
    149                    }
    150
    151                    if (var2)
    152                    {
    153                        this.setFire(8);
    154                    }
    155                }
    156            }
    157
    158            super.onLivingUpdate();
    159        }
    160
    161        /**
    162         * Called when the mob's health reaches 0.
    163         */
    164        public void onDeath(DamageSource par1DamageSource)
    165        {
    166            super.onDeath(par1DamageSource);
    167
    168            if (par1DamageSource.getSourceOfDamage() instanceof EntityArrow && par1DamageSource.getEntity() instanceof EntityPlayer)
    169            {
    170                EntityPlayer var2 = (EntityPlayer)par1DamageSource.getEntity();
    171                double var3 = var2.posX - this.posX;
    172                double var5 = var2.posZ - this.posZ;
    173
    174                if (var3 * var3 + var5 * var5 >= 2500.0D)
    175                {
    176                    var2.triggerAchievement(AchievementList.snipeSkeleton);
    177                }
    178            }
    179        }
    180
    181        /**
    182         * Returns the item ID for the item the mob drops on death.
    183         */
    184        protected int getDropItemId()
    185        {
    186            return Item.arrow.shiftedIndex;
    187        }
    188
    189        /**
    190         * Drop 0-2 items of this living's type
    191         */
    192        protected void dropFewItems(boolean par1, int par2)
    193        {
    194            int var3;
    195            int var4;
    196
    197            if (this.func_82202_m() == 1)
    198            {
    199                var3 = this.rand.nextInt(3 + par2) - 1;
    200
    201                for (var4 = 0; var4 < var3; ++var4)
    202                {
    203                    this.dropItem(Item.coal.shiftedIndex, 1);
    204                }
    205            }
    206            else
    207            {
    208                var3 = this.rand.nextInt(3 + par2);
    209
    210                for (var4 = 0; var4 < var3; ++var4)
    211                {
    212                    this.dropItem(Item.arrow.shiftedIndex, 1);
    213                }
    214            }
    215
    216            var3 = this.rand.nextInt(3 + par2);
    217
    218            for (var4 = 0; var4 < var3; ++var4)
    219            {
    220                this.dropItem(Item.bone.shiftedIndex, 1);
    221            }
    222        }
    223
    224        protected void dropRareDrop(int par1)
    225        {
    226            if (this.func_82202_m() == 1)
    227            {
    228                this.entityDropItem(new ItemStack(Item.field_82799_bQ.shiftedIndex, 1, 1), 0.0F);
    229            }
    230        }
    231
    232        protected void func_82164_bB()
    233        {
    234            super.func_82164_bB();
    235            this.func_70062_b(0, new ItemStack(Item.bow));
    236        }
    237
    238        @SideOnly(Side.CLIENT)
    239
    240        /**
    241         * Returns the texture's file path as a String.
    242         */
    243        public String getTexture()
    244        {
    245            return this.func_82202_m() == 1 ? "/mob/skeleton_wither.png" : super.getTexture();
    246        }
    247
    248        public void func_82163_bD()
    249        {
    250            if (this.worldObj.provider instanceof WorldProviderHell && this.getRNG().nextInt(5) > 0)
    251            {
    252                this.tasks.addTask(4, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
    253                this.func_82201_a(1);
    254                this.func_70062_b(0, new ItemStack(Item.swordStone));
    255            }
    256            else
    257            {
    258                this.tasks.addTask(4, new EntityAIArrowAttack(this, this.moveSpeed, 60, 10.0F));
    259                this.func_82164_bB();
    260                this.func_82162_bC();
    261            }
    262
    263            this.field_82172_bs = this.rand.nextFloat() < field_82181_as[this.worldObj.difficultySetting];
    264
    265            if (this.getCurrentItemOrArmor(4) == null)
    266            {
    267                Calendar var1 = this.worldObj.func_83015_S();
    268
    269                if (var1.get(2) + 1 == 10 && var1.get(5) == 31 && this.rand.nextFloat() < 0.25F)
    270                {
    271                    this.func_70062_b(4, new ItemStack(this.rand.nextFloat() < 0.1F ? Block.pumpkinLantern : Block.pumpkin));
    272                    this.field_82174_bp[4] = 0.0F;
    273                }
    274            }
    275        }
    276
    277        public void func_82196_d(EntityLiving par1EntityLiving)
    278        {
    279            EntityArrow var2 = new EntityArrow(this.worldObj, this, par1EntityLiving, 1.6F, 12.0F);
    280            int var3 = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, this.getHeldItem());
    281            int var4 = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, this.getHeldItem());
    282
    283            if (var3 > 0)
    284            {
    285                var2.setDamage(var2.getDamage() + (double)var3 * 0.5D + 0.5D);
    286            }
    287
    288            if (var4 > 0)
    289            {
    290                var2.setKnockbackStrength(var4);
    291            }
    292
    293            if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, this.getHeldItem()) > 0 || this.func_82202_m() == 1)
    294            {
    295                var2.setFire(100);
    296            }
    297
    298            this.worldObj.playSoundAtEntity(this, "random.bow", 1.0F, 1.0F / (this.getRNG().nextFloat() * 0.4F + 0.8F));
    299            this.worldObj.spawnEntityInWorld(var2);
    300        }
    301
    302        public int func_82202_m()
    303        {
    304            return this.dataWatcher.getWatchableObjectByte(13);
    305        }
    306
    307        public void func_82201_a(int par1)
    308        {
    309            this.dataWatcher.updateObject(13, Byte.valueOf((byte)par1));
    310            this.isImmuneToFire = par1 == 1;
    311
    312            if (par1 == 1)
    313            {
    314                this.setSize(0.72F, 2.16F);
    315            }
    316            else
    317            {
    318                this.setSize(0.6F, 1.8F);
    319            }
    320        }
    321
    322        /**
    323         * (abstract) Protected helper method to read subclass entity data from NBT.
    324         */
    325        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    326        {
    327            super.readEntityFromNBT(par1NBTTagCompound);
    328
    329            if (par1NBTTagCompound.hasKey("SkeletonType"))
    330            {
    331                byte var2 = par1NBTTagCompound.getByte("SkeletonType");
    332                this.func_82201_a(var2);
    333            }
    334
    335            if (this.func_82202_m() == 1)
    336            {
    337                this.tasks.addTask(4, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
    338            }
    339            else
    340            {
    341                this.tasks.addTask(4, new EntityAIArrowAttack(this, this.moveSpeed, 60, 10.0F));
    342            }
    343        }
    344
    345        /**
    346         * (abstract) Protected helper method to write subclass entity data to NBT.
    347         */
    348        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    349        {
    350            super.writeEntityToNBT(par1NBTTagCompound);
    351            par1NBTTagCompound.setByte("SkeletonType", (byte)this.func_82202_m());
    352        }
    353    }