    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.getSkeletonType() == 1 && par1Entity instanceof EntityLiving)
    080                {
    081                    ((EntityLiving)par1Entity).addPotionEffect(new PotionEffect(Potion.wither.id, 200));
    082                }
    083
    084                return true;
    085            }
    086            else
    087            {
    088                return false;
    089            }
    090        }
    091
    092        /**
    093         * Returns the amount of damage a mob should deal.
    094         */
    095        public int getAttackStrength(Entity par1Entity)
    096        {
    097            if (this.getSkeletonType() == 1)
    098            {
    099                ItemStack var2 = this.getHeldItem();
    100                int var3 = 4;
    101
    102                if (var2 != null)
    103                {
    104                    var3 += var2.getDamageVsEntity(this);
    105                }
    106
    107                return var3;
    108            }
    109            else
    110            {
    111                return super.getAttackStrength(par1Entity);
    112            }
    113        }
    114
    115        /**
    116         * Get this Entity's EnumCreatureAttribute
    117         */
    118        public EnumCreatureAttribute getCreatureAttribute()
    119        {
    120            return EnumCreatureAttribute.UNDEAD;
    121        }
    122
    123        /**
    124         * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
    125         * use this to react to sunlight and start to burn.
    126         */
    127        public void onLivingUpdate()
    128        {
    129            if (this.worldObj.isDaytime() && !this.worldObj.isRemote)
    130            {
    131                float var1 = this.getBrightness(1.0F);
    132
    133                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)))
    134                {
    135                    boolean var2 = true;
    136                    ItemStack var3 = this.getCurrentItemOrArmor(4);
    137
    138                    if (var3 != null)
    139                    {
    140                        if (var3.isItemStackDamageable())
    141                        {
    142                            var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2));
    143
    144                            if (var3.getItemDamageForDisplay() >= var3.getMaxDamage())
    145                            {
    146                                this.renderBrokenItemStack(var3);
    147                                this.setCurrentItemOrArmor(4, (ItemStack)null);
    148                            }
    149                        }
    150
    151                        var2 = false;
    152                    }
    153
    154                    if (var2)
    155                    {
    156                        this.setFire(8);
    157                    }
    158                }
    159            }
    160
    161            super.onLivingUpdate();
    162        }
    163
    164        /**
    165         * Called when the mob's health reaches 0.
    166         */
    167        public void onDeath(DamageSource par1DamageSource)
    168        {
    169            super.onDeath(par1DamageSource);
    170
    171            if (par1DamageSource.getSourceOfDamage() instanceof EntityArrow && par1DamageSource.getEntity() instanceof EntityPlayer)
    172            {
    173                EntityPlayer var2 = (EntityPlayer)par1DamageSource.getEntity();
    174                double var3 = var2.posX - this.posX;
    175                double var5 = var2.posZ - this.posZ;
    176
    177                if (var3 * var3 + var5 * var5 >= 2500.0D)
    178                {
    179                    var2.triggerAchievement(AchievementList.snipeSkeleton);
    180                }
    181            }
    182        }
    183
    184        /**
    185         * Returns the item ID for the item the mob drops on death.
    186         */
    187        protected int getDropItemId()
    188        {
    189            return Item.arrow.shiftedIndex;
    190        }
    191
    192        /**
    193         * Drop 0-2 items of this living's type
    194         */
    195        protected void dropFewItems(boolean par1, int par2)
    196        {
    197            int var3;
    198            int var4;
    199
    200            if (this.getSkeletonType() == 1)
    201            {
    202                var3 = this.rand.nextInt(3 + par2) - 1;
    203
    204                for (var4 = 0; var4 < var3; ++var4)
    205                {
    206                    this.dropItem(Item.coal.shiftedIndex, 1);
    207                }
    208            }
    209            else
    210            {
    211                var3 = this.rand.nextInt(3 + par2);
    212
    213                for (var4 = 0; var4 < var3; ++var4)
    214                {
    215                    this.dropItem(Item.arrow.shiftedIndex, 1);
    216                }
    217            }
    218
    219            var3 = this.rand.nextInt(3 + par2);
    220
    221            for (var4 = 0; var4 < var3; ++var4)
    222            {
    223                this.dropItem(Item.bone.shiftedIndex, 1);
    224            }
    225        }
    226
    227        protected void dropRareDrop(int par1)
    228        {
    229            if (this.getSkeletonType() == 1)
    230            {
    231                this.entityDropItem(new ItemStack(Item.skull.shiftedIndex, 1, 1), 0.0F);
    232            }
    233        }
    234
    235        protected void func_82164_bB()
    236        {
    237            super.func_82164_bB();
    238            this.setCurrentItemOrArmor(0, new ItemStack(Item.bow));
    239        }
    240
    241        @SideOnly(Side.CLIENT)
    242
    243        /**
    244         * Returns the texture's file path as a String.
    245         */
    246        public String getTexture()
    247        {
    248            return this.getSkeletonType() == 1 ? "/mob/skeleton_wither.png" : super.getTexture();
    249        }
    250
    251        /**
    252         * Initialize this creature.
    253         */
    254        public void initCreature()
    255        {
    256            if (this.worldObj.provider instanceof WorldProviderHell && this.getRNG().nextInt(5) > 0)
    257            {
    258                this.tasks.addTask(4, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
    259                this.setSkeletonType(1);
    260                this.setCurrentItemOrArmor(0, new ItemStack(Item.swordStone));
    261            }
    262            else
    263            {
    264                this.tasks.addTask(4, new EntityAIArrowAttack(this, this.moveSpeed, 60, 10.0F));
    265                this.func_82164_bB();
    266                this.func_82162_bC();
    267            }
    268
    269            this.canPickUpLoot = this.rand.nextFloat() < field_82181_as[this.worldObj.difficultySetting];
    270
    271            if (this.getCurrentItemOrArmor(4) == null)
    272            {
    273                Calendar var1 = this.worldObj.getCurrentDate();
    274
    275                if (var1.get(2) + 1 == 10 && var1.get(5) == 31 && this.rand.nextFloat() < 0.25F)
    276                {
    277                    this.setCurrentItemOrArmor(4, new ItemStack(this.rand.nextFloat() < 0.1F ? Block.pumpkinLantern : Block.pumpkin));
    278                    this.equipmentDropChances[4] = 0.0F;
    279                }
    280            }
    281        }
    282
    283        /**
    284         * Attack the specified entity using a ranged attack.
    285         */
    286        public void attackEntityWithRangedAttack(EntityLiving par1EntityLiving)
    287        {
    288            EntityArrow var2 = new EntityArrow(this.worldObj, this, par1EntityLiving, 1.6F, 12.0F);
    289            int var3 = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, this.getHeldItem());
    290            int var4 = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, this.getHeldItem());
    291
    292            if (var3 > 0)
    293            {
    294                var2.setDamage(var2.getDamage() + (double)var3 * 0.5D + 0.5D);
    295            }
    296
    297            if (var4 > 0)
    298            {
    299                var2.setKnockbackStrength(var4);
    300            }
    301
    302            if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, this.getHeldItem()) > 0 || this.getSkeletonType() == 1)
    303            {
    304                var2.setFire(100);
    305            }
    306
    307            this.worldObj.playSoundAtEntity(this, "random.bow", 1.0F, 1.0F / (this.getRNG().nextFloat() * 0.4F + 0.8F));
    308            this.worldObj.spawnEntityInWorld(var2);
    309        }
    310
    311        /**
    312         * Return this skeleton's type.
    313         */
    314        public int getSkeletonType()
    315        {
    316            return this.dataWatcher.getWatchableObjectByte(13);
    317        }
    318
    319        /**
    320         * Set this skeleton's type.
    321         */
    322        public void setSkeletonType(int par1)
    323        {
    324            this.dataWatcher.updateObject(13, Byte.valueOf((byte)par1));
    325            this.isImmuneToFire = par1 == 1;
    326
    327            if (par1 == 1)
    328            {
    329                this.setSize(0.72F, 2.16F);
    330            }
    331            else
    332            {
    333                this.setSize(0.6F, 1.8F);
    334            }
    335        }
    336
    337        /**
    338         * (abstract) Protected helper method to read subclass entity data from NBT.
    339         */
    340        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    341        {
    342            super.readEntityFromNBT(par1NBTTagCompound);
    343
    344            if (par1NBTTagCompound.hasKey("SkeletonType"))
    345            {
    346                byte var2 = par1NBTTagCompound.getByte("SkeletonType");
    347                this.setSkeletonType(var2);
    348            }
    349
    350            if (this.getSkeletonType() == 1)
    351            {
    352                this.tasks.addTask(4, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
    353            }
    354            else
    355            {
    356                this.tasks.addTask(4, new EntityAIArrowAttack(this, this.moveSpeed, 60, 10.0F));
    357            }
    358        }
    359
    360        /**
    361         * (abstract) Protected helper method to write subclass entity data to NBT.
    362         */
    363        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    364        {
    365            super.writeEntityToNBT(par1NBTTagCompound);
    366            par1NBTTagCompound.setByte("SkeletonType", (byte)this.getSkeletonType());
    367        }
    368    }