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 EntityZombie extends EntityMob 008 { 009 private int field_82234_d = 0; 010 011 public EntityZombie(World par1World) 012 { 013 super(par1World); 014 this.texture = "/mob/zombie.png"; 015 this.moveSpeed = 0.23F; 016 this.getNavigator().setBreakDoors(true); 017 this.tasks.addTask(0, new EntityAISwimming(this)); 018 this.tasks.addTask(1, new EntityAIBreakDoor(this)); 019 this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false)); 020 this.tasks.addTask(3, new EntityAIAttackOnCollide(this, EntityVillager.class, this.moveSpeed, true)); 021 this.tasks.addTask(4, new EntityAIMoveTwardsRestriction(this, this.moveSpeed)); 022 this.tasks.addTask(5, new EntityAIMoveThroughVillage(this, this.moveSpeed, false)); 023 this.tasks.addTask(6, new EntityAIWander(this, this.moveSpeed)); 024 this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); 025 this.tasks.addTask(7, new EntityAILookIdle(this)); 026 this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); 027 this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 16.0F, 0, true)); 028 this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityVillager.class, 16.0F, 0, false)); 029 } 030 031 /** 032 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown 033 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities. 034 */ 035 public float getSpeedModifier() 036 { 037 return super.getSpeedModifier() * (this.isChild() ? 1.5F : 1.0F); 038 } 039 040 protected void entityInit() 041 { 042 super.entityInit(); 043 this.getDataWatcher().addObject(12, Byte.valueOf((byte)0)); 044 this.getDataWatcher().addObject(13, Byte.valueOf((byte)0)); 045 this.getDataWatcher().addObject(14, Byte.valueOf((byte)0)); 046 } 047 048 @SideOnly(Side.CLIENT) 049 050 /** 051 * Returns the texture's file path as a String. 052 */ 053 public String getTexture() 054 { 055 return this.func_82231_m() ? "/mob/zombie_villager.png" : "/mob/zombie.png"; 056 } 057 058 public int getMaxHealth() 059 { 060 return 20; 061 } 062 063 /** 064 * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue 065 */ 066 public int getTotalArmorValue() 067 { 068 int var1 = super.getTotalArmorValue() + 2; 069 070 if (var1 > 20) 071 { 072 var1 = 20; 073 } 074 075 return var1; 076 } 077 078 /** 079 * Returns true if the newer Entity AI code should be run 080 */ 081 protected boolean isAIEnabled() 082 { 083 return true; 084 } 085 086 /** 087 * If Animal, checks if the age timer is negative 088 */ 089 public boolean isChild() 090 { 091 return this.getDataWatcher().getWatchableObjectByte(12) == 1; 092 } 093 094 public void func_82227_f(boolean par1) 095 { 096 this.getDataWatcher().updateObject(12, Byte.valueOf((byte)1)); 097 } 098 099 public boolean func_82231_m() 100 { 101 return this.getDataWatcher().getWatchableObjectByte(13) == 1; 102 } 103 104 public void func_82229_g(boolean par1) 105 { 106 this.getDataWatcher().updateObject(13, Byte.valueOf((byte)(par1 ? 1 : 0))); 107 } 108 109 /** 110 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 111 * use this to react to sunlight and start to burn. 112 */ 113 public void onLivingUpdate() 114 { 115 if (this.worldObj.isDaytime() && !this.worldObj.isRemote && !this.isChild()) 116 { 117 float var1 = this.getBrightness(1.0F); 118 119 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))) 120 { 121 boolean var2 = true; 122 ItemStack var3 = this.getCurrentItemOrArmor(4); 123 124 if (var3 != null) 125 { 126 if (var3.isItemStackDamageable()) 127 { 128 var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2)); 129 130 if (var3.getItemDamageForDisplay() >= var3.getMaxDamage()) 131 { 132 this.renderBrokenItemStack(var3); 133 this.func_70062_b(4, (ItemStack)null); 134 } 135 } 136 137 var2 = false; 138 } 139 140 if (var2) 141 { 142 this.setFire(8); 143 } 144 } 145 } 146 147 super.onLivingUpdate(); 148 } 149 150 /** 151 * Called to update the entity's position/logic. 152 */ 153 public void onUpdate() 154 { 155 if (!this.worldObj.isRemote && this.func_82230_o()) 156 { 157 int var1 = this.func_82233_q(); 158 this.field_82234_d -= var1; 159 160 if (this.field_82234_d <= 0) 161 { 162 this.func_82232_p(); 163 } 164 } 165 166 super.onUpdate(); 167 } 168 169 public int func_82193_c(Entity par1Entity) 170 { 171 ItemStack var2 = this.getHeldItem(); 172 int var3 = 4; 173 174 if (var2 != null) 175 { 176 var3 += var2.getDamageVsEntity(this); 177 } 178 179 return var3; 180 } 181 182 /** 183 * Returns the sound this mob makes while it's alive. 184 */ 185 protected String getLivingSound() 186 { 187 return "mob.zombie.say"; 188 } 189 190 /** 191 * Returns the sound this mob makes when it is hurt. 192 */ 193 protected String getHurtSound() 194 { 195 return "mob.zombie.hurt"; 196 } 197 198 /** 199 * Returns the sound this mob makes on death. 200 */ 201 protected String getDeathSound() 202 { 203 return "mob.zombie.death"; 204 } 205 206 /** 207 * Plays step sound at given x, y, z for the entity 208 */ 209 protected void playStepSound(int par1, int par2, int par3, int par4) 210 { 211 this.worldObj.playSoundAtEntity(this, "mob.zombie.step", 0.15F, 1.0F); 212 } 213 214 /** 215 * Returns the item ID for the item the mob drops on death. 216 */ 217 protected int getDropItemId() 218 { 219 return Item.rottenFlesh.shiftedIndex; 220 } 221 222 /** 223 * Get this Entity's EnumCreatureAttribute 224 */ 225 public EnumCreatureAttribute getCreatureAttribute() 226 { 227 return EnumCreatureAttribute.UNDEAD; 228 } 229 230 protected void dropRareDrop(int par1) 231 { 232 switch (this.rand.nextInt(3)) 233 { 234 case 0: 235 this.dropItem(Item.ingotIron.shiftedIndex, 1); 236 break; 237 case 1: 238 this.dropItem(Item.field_82797_bK.shiftedIndex, 1); 239 break; 240 case 2: 241 this.dropItem(Item.field_82794_bL.shiftedIndex, 1); 242 } 243 } 244 245 protected void func_82164_bB() 246 { 247 super.func_82164_bB(); 248 249 if (this.rand.nextFloat() < (this.worldObj.difficultySetting == 3 ? 0.05F : 0.01F)) 250 { 251 int var1 = this.rand.nextInt(3); 252 253 if (var1 == 0) 254 { 255 this.func_70062_b(0, new ItemStack(Item.swordSteel)); 256 } 257 else 258 { 259 this.func_70062_b(0, new ItemStack(Item.shovelSteel)); 260 } 261 } 262 } 263 264 /** 265 * (abstract) Protected helper method to write subclass entity data to NBT. 266 */ 267 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 268 { 269 super.writeEntityToNBT(par1NBTTagCompound); 270 271 if (this.isChild()) 272 { 273 par1NBTTagCompound.setBoolean("IsBaby", true); 274 } 275 276 if (this.func_82231_m()) 277 { 278 par1NBTTagCompound.setBoolean("IsVillager", true); 279 } 280 281 par1NBTTagCompound.setInteger("ConversionTime", this.func_82230_o() ? this.field_82234_d : -1); 282 } 283 284 /** 285 * (abstract) Protected helper method to read subclass entity data from NBT. 286 */ 287 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 288 { 289 super.readEntityFromNBT(par1NBTTagCompound); 290 291 if (par1NBTTagCompound.getBoolean("IsBaby")) 292 { 293 this.func_82227_f(true); 294 } 295 296 if (par1NBTTagCompound.getBoolean("IsVillager")) 297 { 298 this.func_82229_g(true); 299 } 300 301 if (par1NBTTagCompound.hasKey("ConversionTime") && par1NBTTagCompound.getInteger("ConversionTime") > -1) 302 { 303 this.func_82228_a(par1NBTTagCompound.getInteger("ConversionTime")); 304 } 305 } 306 307 /** 308 * This method gets called when the entity kills another one. 309 */ 310 public void onKillEntity(EntityLiving par1EntityLiving) 311 { 312 super.onKillEntity(par1EntityLiving); 313 314 if (this.worldObj.difficultySetting >= 2 && par1EntityLiving instanceof EntityVillager) 315 { 316 if (this.worldObj.difficultySetting == 2 && this.rand.nextBoolean()) 317 { 318 return; 319 } 320 321 EntityZombie var2 = new EntityZombie(this.worldObj); 322 var2.func_82149_j(par1EntityLiving); 323 this.worldObj.setEntityDead(par1EntityLiving); 324 var2.func_82163_bD(); 325 var2.func_82229_g(true); 326 327 if (par1EntityLiving.isChild()) 328 { 329 var2.func_82227_f(true); 330 } 331 332 this.worldObj.spawnEntityInWorld(var2); 333 this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1016, (int)this.posX, (int)this.posY, (int)this.posZ, 0); 334 } 335 } 336 337 public void func_82163_bD() 338 { 339 this.field_82172_bs = this.rand.nextFloat() < field_82181_as[this.worldObj.difficultySetting]; 340 341 if (this.worldObj.rand.nextFloat() < 0.05F) 342 { 343 this.func_82229_g(true); 344 } 345 346 this.func_82164_bB(); 347 this.func_82162_bC(); 348 349 if (this.getCurrentItemOrArmor(4) == null) 350 { 351 Calendar var1 = this.worldObj.func_83015_S(); 352 353 if (var1.get(2) + 1 == 10 && var1.get(5) == 31 && this.rand.nextFloat() < 0.25F) 354 { 355 this.func_70062_b(4, new ItemStack(this.rand.nextFloat() < 0.1F ? Block.pumpkinLantern : Block.pumpkin)); 356 this.field_82174_bp[4] = 0.0F; 357 } 358 } 359 } 360 361 /** 362 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 363 */ 364 public boolean interact(EntityPlayer par1EntityPlayer) 365 { 366 ItemStack var2 = par1EntityPlayer.getCurrentEquippedItem(); 367 368 if (var2 != null && var2.getItem() == Item.appleGold && var2.getItemDamage() == 0 && this.func_82231_m() && this.isPotionActive(Potion.weakness)) 369 { 370 if (!par1EntityPlayer.capabilities.isCreativeMode) 371 { 372 --var2.stackSize; 373 } 374 375 if (var2.stackSize <= 0) 376 { 377 par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null); 378 } 379 380 if (!this.worldObj.isRemote) 381 { 382 this.func_82228_a(this.rand.nextInt(2401) + 3600); 383 } 384 385 return true; 386 } 387 else 388 { 389 return false; 390 } 391 } 392 393 protected void func_82228_a(int par1) 394 { 395 this.field_82234_d = par1; 396 this.getDataWatcher().updateObject(14, Byte.valueOf((byte)1)); 397 this.func_82170_o(Potion.weakness.id); 398 this.addPotionEffect(new PotionEffect(Potion.damageBoost.id, par1, Math.min(this.worldObj.difficultySetting - 1, 0))); 399 this.worldObj.setEntityState(this, (byte)16); 400 } 401 402 @SideOnly(Side.CLIENT) 403 public void handleHealthUpdate(byte par1) 404 { 405 if (par1 == 16) 406 { 407 this.worldObj.playSound(this.posX + 0.5D, this.posY + 0.5D, this.posZ + 0.5D, "mob.zombie.remedy", 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F); 408 } 409 else 410 { 411 super.handleHealthUpdate(par1); 412 } 413 } 414 415 public boolean func_82230_o() 416 { 417 return this.getDataWatcher().getWatchableObjectByte(14) == 1; 418 } 419 420 protected void func_82232_p() 421 { 422 EntityVillager var1 = new EntityVillager(this.worldObj); 423 var1.func_82149_j(this); 424 var1.func_82163_bD(); 425 var1.func_82187_q(); 426 427 if (this.isChild()) 428 { 429 var1.setGrowingAge(-24000); 430 } 431 432 this.worldObj.setEntityDead(this); 433 this.worldObj.spawnEntityInWorld(var1); 434 var1.addPotionEffect(new PotionEffect(Potion.confusion.id, 200, 0)); 435 this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1017, (int)this.posX, (int)this.posY, (int)this.posZ, 0); 436 } 437 438 protected int func_82233_q() 439 { 440 int var1 = 1; 441 442 if (this.rand.nextFloat() < 0.01F) 443 { 444 int var2 = 0; 445 446 for (int var3 = (int)this.posX - 4; var3 < (int)this.posX + 4 && var2 < 14; ++var3) 447 { 448 for (int var4 = (int)this.posY - 4; var4 < (int)this.posY + 4 && var2 < 14; ++var4) 449 { 450 for (int var5 = (int)this.posZ - 4; var5 < (int)this.posZ + 4 && var2 < 14; ++var5) 451 { 452 int var6 = this.worldObj.getBlockId(var3, var4, var5); 453 454 if (var6 == Block.fenceIron.blockID || var6 == Block.bed.blockID) 455 { 456 if (this.rand.nextFloat() < 0.3F) 457 { 458 ++var1; 459 } 460 461 ++var2; 462 } 463 } 464 } 465 } 466 } 467 468 return var1; 469 } 470 }