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