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.List; 006 007 public class EntityWither extends EntityMob implements IBossDisplayData, IRangedAttackMob 008 { 009 private float[] field_82220_d = new float[2]; 010 private float[] field_82221_e = new float[2]; 011 private float[] field_82217_f = new float[2]; 012 private float[] field_82218_g = new float[2]; 013 private int[] field_82223_h = new int[2]; 014 private int[] field_82224_i = new int[2]; 015 private int field_82222_j; 016 private static final IEntitySelector field_82219_bJ = new EntityWitherAttackFilter(); 017 018 public EntityWither(World par1World) 019 { 020 super(par1World); 021 this.setEntityHealth(this.getMaxHealth()); 022 this.texture = "/mob/wither.png"; 023 this.setSize(0.9F, 4.0F); 024 this.isImmuneToFire = true; 025 this.moveSpeed = 0.6F; 026 this.getNavigator().setCanSwim(true); 027 this.tasks.addTask(0, new EntityAISwimming(this)); 028 this.tasks.addTask(2, new EntityAIArrowAttack(this, this.moveSpeed, 40, 20.0F)); 029 this.tasks.addTask(5, new EntityAIWander(this, this.moveSpeed)); 030 this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F)); 031 this.tasks.addTask(7, new EntityAILookIdle(this)); 032 this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); 033 this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 30.0F, 0, false, false, field_82219_bJ)); 034 this.experienceValue = 50; 035 } 036 037 protected void entityInit() 038 { 039 super.entityInit(); 040 this.dataWatcher.addObject(16, new Integer(100)); 041 this.dataWatcher.addObject(17, new Integer(0)); 042 this.dataWatcher.addObject(18, new Integer(0)); 043 this.dataWatcher.addObject(19, new Integer(0)); 044 this.dataWatcher.addObject(20, new Integer(0)); 045 } 046 047 /** 048 * (abstract) Protected helper method to write subclass entity data to NBT. 049 */ 050 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 051 { 052 super.writeEntityToNBT(par1NBTTagCompound); 053 par1NBTTagCompound.setInteger("Invul", this.func_82212_n()); 054 } 055 056 /** 057 * (abstract) Protected helper method to read subclass entity data from NBT. 058 */ 059 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 060 { 061 super.readEntityFromNBT(par1NBTTagCompound); 062 this.func_82215_s(par1NBTTagCompound.getInteger("Invul")); 063 this.dataWatcher.updateObject(16, Integer.valueOf(this.health)); 064 } 065 066 @SideOnly(Side.CLIENT) 067 public float getShadowSize() 068 { 069 return this.height / 8.0F; 070 } 071 072 /** 073 * Returns the sound this mob makes while it's alive. 074 */ 075 protected String getLivingSound() 076 { 077 return "mob.wither.idle"; 078 } 079 080 /** 081 * Returns the sound this mob makes when it is hurt. 082 */ 083 protected String getHurtSound() 084 { 085 return "mob.wither.hurt"; 086 } 087 088 /** 089 * Returns the sound this mob makes on death. 090 */ 091 protected String getDeathSound() 092 { 093 return "mob.wither.death"; 094 } 095 096 @SideOnly(Side.CLIENT) 097 098 /** 099 * Returns the texture's file path as a String. 100 */ 101 public String getTexture() 102 { 103 int var1 = this.func_82212_n(); 104 return var1 > 0 && (var1 > 80 || var1 / 5 % 2 != 1) ? "/mob/wither_invul.png" : "/mob/wither.png"; 105 } 106 107 /** 108 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 109 * use this to react to sunlight and start to burn. 110 */ 111 public void onLivingUpdate() 112 { 113 if (!this.worldObj.isRemote) 114 { 115 this.dataWatcher.updateObject(16, Integer.valueOf(this.health)); 116 } 117 118 this.motionY *= 0.6000000238418579D; 119 double var4; 120 double var6; 121 double var8; 122 123 if (!this.worldObj.isRemote && this.func_82203_t(0) > 0) 124 { 125 Entity var1 = this.worldObj.getEntityByID(this.func_82203_t(0)); 126 127 if (var1 != null) 128 { 129 if (this.posY < var1.posY || !this.func_82205_o() && this.posY < var1.posY + 5.0D) 130 { 131 if (this.motionY < 0.0D) 132 { 133 this.motionY = 0.0D; 134 } 135 136 this.motionY += (0.5D - this.motionY) * 0.6000000238418579D; 137 } 138 139 double var2 = var1.posX - this.posX; 140 var4 = var1.posZ - this.posZ; 141 var6 = var2 * var2 + var4 * var4; 142 143 if (var6 > 9.0D) 144 { 145 var8 = (double)MathHelper.sqrt_double(var6); 146 this.motionX += (var2 / var8 * 0.5D - this.motionX) * 0.6000000238418579D; 147 this.motionZ += (var4 / var8 * 0.5D - this.motionZ) * 0.6000000238418579D; 148 } 149 } 150 } 151 152 if (this.motionX * this.motionX + this.motionZ * this.motionZ > 0.05000000074505806D) 153 { 154 this.rotationYaw = (float)Math.atan2(this.motionZ, this.motionX) * (180F / (float)Math.PI) - 90.0F; 155 } 156 157 super.onLivingUpdate(); 158 int var20; 159 160 for (var20 = 0; var20 < 2; ++var20) 161 { 162 this.field_82218_g[var20] = this.field_82221_e[var20]; 163 this.field_82217_f[var20] = this.field_82220_d[var20]; 164 } 165 166 int var21; 167 168 for (var20 = 0; var20 < 2; ++var20) 169 { 170 var21 = this.func_82203_t(var20 + 1); 171 Entity var3 = null; 172 173 if (var21 > 0) 174 { 175 var3 = this.worldObj.getEntityByID(var21); 176 } 177 178 if (var3 != null) 179 { 180 var4 = this.func_82214_u(var20 + 1); 181 var6 = this.func_82208_v(var20 + 1); 182 var8 = this.func_82213_w(var20 + 1); 183 double var10 = var3.posX - var4; 184 double var12 = var3.posY + (double)var3.getEyeHeight() - var6; 185 double var14 = var3.posZ - var8; 186 double var16 = (double)MathHelper.sqrt_double(var10 * var10 + var14 * var14); 187 float var18 = (float)(Math.atan2(var14, var10) * 180.0D / Math.PI) - 90.0F; 188 float var19 = (float)(-(Math.atan2(var12, var16) * 180.0D / Math.PI)); 189 this.field_82220_d[var20] = this.func_82204_b(this.field_82220_d[var20], var19, 40.0F); 190 this.field_82221_e[var20] = this.func_82204_b(this.field_82221_e[var20], var18, 10.0F); 191 } 192 else 193 { 194 this.field_82221_e[var20] = this.func_82204_b(this.field_82221_e[var20], this.renderYawOffset, 10.0F); 195 } 196 } 197 198 boolean var22 = this.func_82205_o(); 199 200 for (var21 = 0; var21 < 3; ++var21) 201 { 202 double var23 = this.func_82214_u(var21); 203 double var5 = this.func_82208_v(var21); 204 double var7 = this.func_82213_w(var21); 205 this.worldObj.spawnParticle("smoke", var23 + this.rand.nextGaussian() * 0.30000001192092896D, var5 + this.rand.nextGaussian() * 0.30000001192092896D, var7 + this.rand.nextGaussian() * 0.30000001192092896D, 0.0D, 0.0D, 0.0D); 206 207 if (var22 && this.worldObj.rand.nextInt(4) == 0) 208 { 209 this.worldObj.spawnParticle("mobSpell", var23 + this.rand.nextGaussian() * 0.30000001192092896D, var5 + this.rand.nextGaussian() * 0.30000001192092896D, var7 + this.rand.nextGaussian() * 0.30000001192092896D, 0.699999988079071D, 0.699999988079071D, 0.5D); 210 } 211 } 212 213 if (this.func_82212_n() > 0) 214 { 215 for (var21 = 0; var21 < 3; ++var21) 216 { 217 this.worldObj.spawnParticle("mobSpell", this.posX + this.rand.nextGaussian() * 1.0D, this.posY + (double)(this.rand.nextFloat() * 3.3F), this.posZ + this.rand.nextGaussian() * 1.0D, 0.699999988079071D, 0.699999988079071D, 0.8999999761581421D); 218 } 219 } 220 } 221 222 protected void updateAITasks() 223 { 224 int var1; 225 226 if (this.func_82212_n() > 0) 227 { 228 var1 = this.func_82212_n() - 1; 229 230 if (var1 <= 0) 231 { 232 this.worldObj.newExplosion(this, this.posX, this.posY + (double)this.getEyeHeight(), this.posZ, 7.0F, false, this.worldObj.func_82736_K().func_82766_b("mobGriefing")); 233 this.worldObj.func_82739_e(1013, (int)this.posX, (int)this.posY, (int)this.posZ, 0); 234 } 235 236 this.func_82215_s(var1); 237 238 if (this.ticksExisted % 10 == 0) 239 { 240 this.heal(10); 241 } 242 } 243 else 244 { 245 super.updateAITasks(); 246 int var13; 247 248 for (var1 = 1; var1 < 3; ++var1) 249 { 250 if (this.ticksExisted >= this.field_82223_h[var1 - 1]) 251 { 252 this.field_82223_h[var1 - 1] = this.ticksExisted + 10 + this.rand.nextInt(10); 253 254 if (this.worldObj.difficultySetting >= 2) 255 { 256 int var10001 = var1 - 1; 257 int var10003 = this.field_82224_i[var1 - 1]; 258 this.field_82224_i[var10001] = this.field_82224_i[var1 - 1] + 1; 259 260 if (var10003 > 15) 261 { 262 float var2 = 10.0F; 263 float var3 = 5.0F; 264 double var4 = MathHelper.func_82716_a(this.rand, this.posX - (double)var2, this.posX + (double)var2); 265 double var6 = MathHelper.func_82716_a(this.rand, this.posY - (double)var3, this.posY + (double)var3); 266 double var8 = MathHelper.func_82716_a(this.rand, this.posZ - (double)var2, this.posZ + (double)var2); 267 this.func_82209_a(var1 + 1, var4, var6, var8, true); 268 this.field_82224_i[var1 - 1] = 0; 269 } 270 } 271 272 var13 = this.func_82203_t(var1); 273 274 if (var13 > 0) 275 { 276 Entity var15 = this.worldObj.getEntityByID(var13); 277 278 if (var15 != null && var15.isEntityAlive() && this.getDistanceSqToEntity(var15) <= 900.0D && this.canEntityBeSeen(var15)) 279 { 280 this.func_82216_a(var1 + 1, (EntityLiving)var15); 281 this.field_82223_h[var1 - 1] = this.ticksExisted + 40 + this.rand.nextInt(20); 282 this.field_82224_i[var1 - 1] = 0; 283 } 284 else 285 { 286 this.func_82211_c(var1, 0); 287 } 288 } 289 else 290 { 291 List var14 = this.worldObj.func_82733_a(EntityLiving.class, this.boundingBox.expand(20.0D, 8.0D, 20.0D), field_82219_bJ); 292 293 for (int var17 = 0; var17 < 10 && !var14.isEmpty(); ++var17) 294 { 295 EntityLiving var5 = (EntityLiving)var14.get(this.rand.nextInt(var14.size())); 296 297 if (var5 != this && var5.isEntityAlive() && this.canEntityBeSeen(var5)) 298 { 299 if (var5 instanceof EntityPlayer) 300 { 301 if (!((EntityPlayer)var5).capabilities.disableDamage) 302 { 303 this.func_82211_c(var1, var5.entityId); 304 } 305 } 306 else 307 { 308 this.func_82211_c(var1, var5.entityId); 309 } 310 311 break; 312 } 313 314 var14.remove(var5); 315 } 316 } 317 } 318 } 319 320 if (this.getAttackTarget() != null) 321 { 322 this.func_82211_c(0, this.getAttackTarget().entityId); 323 } 324 else 325 { 326 this.func_82211_c(0, 0); 327 } 328 329 if (this.field_82222_j > 0) 330 { 331 --this.field_82222_j; 332 333 if (this.field_82222_j == 0 && this.worldObj.func_82736_K().func_82766_b("mobGriefing")) 334 { 335 var1 = MathHelper.floor_double(this.posY); 336 var13 = MathHelper.floor_double(this.posX); 337 int var16 = MathHelper.floor_double(this.posZ); 338 boolean var19 = false; 339 340 for (int var18 = -1; var18 <= 1; ++var18) 341 { 342 for (int var20 = -1; var20 <= 1; ++var20) 343 { 344 for (int var7 = 0; var7 <= 3; ++var7) 345 { 346 int var21 = var13 + var18; 347 int var9 = var1 + var7; 348 int var10 = var16 + var20; 349 int var11 = this.worldObj.getBlockId(var21, var9, var10); 350 351 if (var11 > 0 && var11 != Block.bedrock.blockID) 352 { 353 int var12 = this.worldObj.getBlockMetadata(var21, var9, var10); 354 this.worldObj.playAuxSFX(2001, var21, var9, var10, var11 + (var12 << 12)); 355 Block.blocksList[var11].dropBlockAsItem(this.worldObj, var21, var9, var10, var12, 0); 356 this.worldObj.setBlockWithNotify(var21, var9, var10, 0); 357 var19 = true; 358 } 359 } 360 } 361 } 362 363 if (var19) 364 { 365 this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1012, (int)this.posX, (int)this.posY, (int)this.posZ, 0); 366 } 367 } 368 } 369 370 if (this.ticksExisted % 20 == 0) 371 { 372 this.heal(1); 373 } 374 } 375 } 376 377 public void func_82206_m() 378 { 379 this.func_82215_s(220); 380 this.setEntityHealth(this.getMaxHealth() / 3); 381 } 382 383 /** 384 * Sets the Entity inside a web block. 385 */ 386 public void setInWeb() {} 387 388 /** 389 * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue 390 */ 391 public int getTotalArmorValue() 392 { 393 return 4; 394 } 395 396 private double func_82214_u(int par1) 397 { 398 if (par1 <= 0) 399 { 400 return this.posX; 401 } 402 else 403 { 404 float var2 = (this.renderYawOffset + (float)(180 * (par1 - 1))) / 180.0F * (float)Math.PI; 405 float var3 = MathHelper.cos(var2); 406 return this.posX + (double)var3 * 1.3D; 407 } 408 } 409 410 private double func_82208_v(int par1) 411 { 412 return par1 <= 0 ? this.posY + 3.0D : this.posY + 2.2D; 413 } 414 415 private double func_82213_w(int par1) 416 { 417 if (par1 <= 0) 418 { 419 return this.posZ; 420 } 421 else 422 { 423 float var2 = (this.renderYawOffset + (float)(180 * (par1 - 1))) / 180.0F * (float)Math.PI; 424 float var3 = MathHelper.sin(var2); 425 return this.posZ + (double)var3 * 1.3D; 426 } 427 } 428 429 private float func_82204_b(float par1, float par2, float par3) 430 { 431 float var4 = MathHelper.wrapAngleTo180_float(par2 - par1); 432 433 if (var4 > par3) 434 { 435 var4 = par3; 436 } 437 438 if (var4 < -par3) 439 { 440 var4 = -par3; 441 } 442 443 return par1 + var4; 444 } 445 446 private void func_82216_a(int par1, EntityLiving par2EntityLiving) 447 { 448 this.func_82209_a(par1, par2EntityLiving.posX, par2EntityLiving.posY + (double)par2EntityLiving.getEyeHeight() * 0.5D, par2EntityLiving.posZ, par1 == 0 && this.rand.nextFloat() < 0.001F); 449 } 450 451 private void func_82209_a(int par1, double par2, double par4, double par6, boolean par8) 452 { 453 this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1014, (int)this.posX, (int)this.posY, (int)this.posZ, 0); 454 double var9 = this.func_82214_u(par1); 455 double var11 = this.func_82208_v(par1); 456 double var13 = this.func_82213_w(par1); 457 double var15 = par2 - var9; 458 double var17 = par4 - var11; 459 double var19 = par6 - var13; 460 EntityWitherSkull var21 = new EntityWitherSkull(this.worldObj, this, var15, var17, var19); 461 462 if (par8) 463 { 464 var21.func_82343_e(true); 465 } 466 467 var21.posY = var11; 468 var21.posX = var9; 469 var21.posZ = var13; 470 this.worldObj.spawnEntityInWorld(var21); 471 } 472 473 public void func_82196_d(EntityLiving par1EntityLiving) 474 { 475 this.func_82216_a(0, par1EntityLiving); 476 } 477 478 /** 479 * Called when the entity is attacked. 480 */ 481 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 482 { 483 if (par1DamageSource == DamageSource.drown) 484 { 485 return false; 486 } 487 else if (this.func_82212_n() > 0) 488 { 489 return false; 490 } 491 else 492 { 493 Entity var3; 494 495 if (this.func_82205_o()) 496 { 497 var3 = par1DamageSource.getSourceOfDamage(); 498 499 if (var3 instanceof EntityArrow) 500 { 501 return false; 502 } 503 } 504 505 var3 = par1DamageSource.getEntity(); 506 507 if (var3 != null && !(var3 instanceof EntityPlayer) && var3 instanceof EntityLiving && ((EntityLiving)var3).getCreatureAttribute() == this.getCreatureAttribute()) 508 { 509 return false; 510 } 511 else 512 { 513 if (this.field_82222_j <= 0) 514 { 515 this.field_82222_j = 20; 516 } 517 518 for (int var4 = 0; var4 < this.field_82224_i.length; ++var4) 519 { 520 this.field_82224_i[var4] += 3; 521 } 522 523 return super.attackEntityFrom(par1DamageSource, par2); 524 } 525 } 526 } 527 528 /** 529 * Drop 0-2 items of this living's type 530 */ 531 protected void dropFewItems(boolean par1, int par2) 532 { 533 this.dropItem(Item.field_82792_bS.shiftedIndex, 1); 534 } 535 536 /** 537 * Makes the entity despawn if requirements are reached 538 */ 539 protected void despawnEntity() 540 { 541 this.entityAge = 0; 542 } 543 544 @SideOnly(Side.CLIENT) 545 public int getBrightnessForRender(float par1) 546 { 547 return 15728880; 548 } 549 550 /** 551 * Returns true if other Entities should be prevented from moving through this Entity. 552 */ 553 public boolean canBeCollidedWith() 554 { 555 return !this.isDead; 556 } 557 558 /** 559 * Returns the health points of the dragon. 560 */ 561 public int getDragonHealth() 562 { 563 return this.dataWatcher.getWatchableObjectInt(16); 564 } 565 566 /** 567 * Called when the mob is falling. Calculates and applies fall damage. 568 */ 569 protected void fall(float par1) {} 570 571 /** 572 * adds a PotionEffect to the entity 573 */ 574 public void addPotionEffect(PotionEffect par1PotionEffect) {} 575 576 /** 577 * Returns true if the newer Entity AI code should be run 578 */ 579 protected boolean isAIEnabled() 580 { 581 return true; 582 } 583 584 public int getMaxHealth() 585 { 586 return 300; 587 } 588 589 @SideOnly(Side.CLIENT) 590 public float func_82207_a(int par1) 591 { 592 return this.field_82221_e[par1]; 593 } 594 595 @SideOnly(Side.CLIENT) 596 public float func_82210_r(int par1) 597 { 598 return this.field_82220_d[par1]; 599 } 600 601 public int func_82212_n() 602 { 603 return this.dataWatcher.getWatchableObjectInt(20); 604 } 605 606 public void func_82215_s(int par1) 607 { 608 this.dataWatcher.updateObject(20, Integer.valueOf(par1)); 609 } 610 611 public int func_82203_t(int par1) 612 { 613 return this.dataWatcher.getWatchableObjectInt(17 + par1); 614 } 615 616 public void func_82211_c(int par1, int par2) 617 { 618 this.dataWatcher.updateObject(17 + par1, Integer.valueOf(par2)); 619 } 620 621 public boolean func_82205_o() 622 { 623 return this.getDragonHealth() <= this.getMaxHealth() / 2; 624 } 625 626 /** 627 * Get this Entity's EnumCreatureAttribute 628 */ 629 public EnumCreatureAttribute getCreatureAttribute() 630 { 631 return EnumCreatureAttribute.UNDEAD; 632 } 633 }