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 }