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