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    }