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