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.Collection; 006 import java.util.HashMap; 007 import java.util.Iterator; 008 import java.util.List; 009 import java.util.Random; 010 import net.minecraftforge.common.ForgeHooks; 011 import net.minecraftforge.common.MinecraftForge; 012 import net.minecraftforge.event.entity.living.*; 013 import static net.minecraftforge.event.entity.living.LivingEvent.*; 014 015 public abstract class EntityLiving extends Entity 016 { 017 private static final float[] field_82177_b = new float[] {0.0F, 0.0F, 0.005F, 0.01F}; 018 private static final float[] field_82178_c = new float[] {0.0F, 0.0F, 0.05F, 0.1F}; 019 private static final float[] field_82176_d = new float[] {0.0F, 0.0F, 0.005F, 0.02F}; 020 public static final float[] field_82181_as = new float[] {0.0F, 0.01F, 0.07F, 0.2F}; 021 public int maxHurtResistantTime = 20; 022 public float field_70769_ao; 023 public float field_70770_ap; 024 public float renderYawOffset = 0.0F; 025 public float prevRenderYawOffset = 0.0F; 026 027 /** Entity head rotation yaw */ 028 public float rotationYawHead = 0.0F; 029 030 /** Entity head rotation yaw at previous tick */ 031 public float prevRotationYawHead = 0.0F; 032 protected float field_70768_au; 033 protected float field_70766_av; 034 protected float field_70764_aw; 035 protected float field_70763_ax; 036 protected boolean field_70753_ay = true; 037 038 /** the path for the texture of this entityLiving */ 039 protected String texture = "/mob/char.png"; 040 protected boolean field_70740_aA = true; 041 protected float field_70741_aB = 0.0F; 042 043 /** 044 * a string holding the type of entity it is currently only implemented in entityPlayer(as 'humanoid') 045 */ 046 protected String entityType = null; 047 protected float field_70743_aD = 1.0F; 048 049 /** The score value of the Mob, the amount of points the mob is worth. */ 050 protected int scoreValue = 0; 051 protected float field_70745_aF = 0.0F; 052 053 /** 054 * A factor used to determine how far this entity will move each tick if it is walking on land. Adjusted by speed, 055 * and slipperiness of the current block. 056 */ 057 public float landMovementFactor = 0.1F; 058 059 /** 060 * A factor used to determine how far this entity will move each tick if it is jumping or falling. 061 */ 062 public float jumpMovementFactor = 0.02F; 063 public float prevSwingProgress; 064 public float swingProgress; 065 protected int health = this.getMaxHealth(); 066 public int prevHealth; 067 068 /** 069 * in each step in the damage calculations, this is set to the 'carryover' that would result if someone was damaged 070 * .25 hearts (for example), and added to the damage in the next step 071 */ 072 public int carryoverDamage; 073 074 /** Number of ticks since this EntityLiving last produced its sound */ 075 public int livingSoundTime; 076 077 /** 078 * The amount of time remaining this entity should act 'hurt'. (Visual appearance of red tint) 079 */ 080 public int hurtTime; 081 082 /** What the hurt time was max set to last. */ 083 public int maxHurtTime; 084 085 /** The yaw at which this entity was last attacked from. */ 086 public float attackedAtYaw = 0.0F; 087 088 /** 089 * The amount of time remaining this entity should act 'dead', i.e. have a corpse in the world. 090 */ 091 public int deathTime = 0; 092 public int attackTime = 0; 093 public float prevCameraPitch; 094 public float cameraPitch; 095 096 /** 097 * This gets set on entity death, but never used. Looks like a duplicate of isDead 098 */ 099 protected boolean dead = false; 100 101 /** The experience points the Entity gives. */ 102 public int experienceValue; 103 public int field_70731_aW = -1; 104 public float field_70730_aX = (float)(Math.random() * 0.8999999761581421D + 0.10000000149011612D); 105 public float prevLegYaw; 106 public float legYaw; 107 108 /** 109 * Only relevant when legYaw is not 0(the entity is moving). Influences where in its swing legs and arms currently 110 * are. 111 */ 112 public float legSwing; 113 114 /** The most recent player that has attacked this entity */ 115 protected EntityPlayer attackingPlayer = null; 116 117 /** 118 * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity 119 * should drop items on death. 120 */ 121 protected int recentlyHit = 0; 122 123 /** is only being set, has no uses as of MC 1.1 */ 124 private EntityLiving entityLivingToAttack = null; 125 private int revengeTimer = 0; 126 private EntityLiving lastAttackingEntity = null; 127 128 /** 129 * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity 130 * should drop items on death. 131 */ 132 public int arrowHitTempCounter = 0; 133 public int arrowHitTimer = 0; 134 protected HashMap activePotionsMap = new HashMap(); 135 136 /** Whether the DataWatcher needs to be updated with the active potions */ 137 private boolean potionsNeedUpdate = true; 138 private int field_70748_f; 139 private EntityLookHelper lookHelper; 140 private EntityMoveHelper moveHelper; 141 142 /** Entity jumping helper */ 143 private EntityJumpHelper jumpHelper; 144 private EntityBodyHelper bodyHelper; 145 private PathNavigate navigator; 146 public final EntityAITasks tasks; 147 protected final EntityAITasks targetTasks; 148 149 /** The active target the Task system uses for tracking */ 150 private EntityLiving attackTarget; 151 private EntitySenses senses; 152 private float AIMoveSpeed; 153 private ChunkCoordinates homePosition = new ChunkCoordinates(0, 0, 0); 154 155 /** If -1 there is no maximum distance */ 156 private float maximumHomeDistance = -1.0F; 157 private ItemStack[] field_82182_bS = new ItemStack[5]; 158 protected float[] field_82174_bp = new float[5]; 159 private ItemStack[] field_82180_bT = new ItemStack[5]; 160 public boolean field_82175_bq = false; 161 public int field_82173_br = 0; 162 protected boolean field_82172_bs = false; 163 private boolean field_82179_bU = false; 164 protected boolean field_83001_bt = false; 165 166 /** 167 * The number of updates over which the new position and rotation are to be applied to the entity. 168 */ 169 protected int newPosRotationIncrements; 170 171 /** The new X position to be applied to the entity. */ 172 protected double newPosX; 173 174 /** The new Y position to be applied to the entity. */ 175 protected double newPosY; 176 177 /** The new Z position to be applied to the entity. */ 178 protected double newPosZ; 179 180 /** The new yaw rotation to be applied to the entity. */ 181 protected double newRotationYaw; 182 183 /** The new yaw rotation to be applied to the entity. */ 184 protected double newRotationPitch; 185 float field_70706_bo = 0.0F; 186 187 /** Amount of damage taken in last hit, in half-hearts */ 188 protected int lastDamage = 0; 189 190 /** Holds the living entity age, used to control the despawn. */ 191 protected int entityAge = 0; 192 protected float moveStrafing; 193 protected float moveForward; 194 protected float randomYawVelocity; 195 196 /** used to check whether entity is jumping. */ 197 public boolean isJumping = false; 198 protected float defaultPitch = 0.0F; 199 protected float moveSpeed = 0.7F; 200 201 /** Number of ticks since last jump */ 202 private int jumpTicks = 0; 203 204 /** This entity's current target. */ 205 private Entity currentTarget; 206 207 /** How long to keep a specific target entity */ 208 protected int numTicksToChaseTarget = 0; 209 210 public EntityLiving(World par1World) 211 { 212 super(par1World); 213 this.preventEntitySpawning = true; 214 this.tasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null); 215 this.targetTasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null); 216 this.lookHelper = new EntityLookHelper(this); 217 this.moveHelper = new EntityMoveHelper(this); 218 this.jumpHelper = new EntityJumpHelper(this); 219 this.bodyHelper = new EntityBodyHelper(this); 220 this.navigator = new PathNavigate(this, par1World, 16.0F); 221 this.senses = new EntitySenses(this); 222 this.field_70770_ap = (float)(Math.random() + 1.0D) * 0.01F; 223 this.setPosition(this.posX, this.posY, this.posZ); 224 this.field_70769_ao = (float)Math.random() * 12398.0F; 225 this.rotationYaw = (float)(Math.random() * Math.PI * 2.0D); 226 this.rotationYawHead = this.rotationYaw; 227 228 for (int var2 = 0; var2 < this.field_82174_bp.length; ++var2) 229 { 230 this.field_82174_bp[var2] = 0.05F; 231 } 232 233 this.stepHeight = 0.5F; 234 } 235 236 public EntityLookHelper getLookHelper() 237 { 238 return this.lookHelper; 239 } 240 241 public EntityMoveHelper getMoveHelper() 242 { 243 return this.moveHelper; 244 } 245 246 public EntityJumpHelper getJumpHelper() 247 { 248 return this.jumpHelper; 249 } 250 251 public PathNavigate getNavigator() 252 { 253 return this.navigator; 254 } 255 256 /** 257 * returns the EntitySenses Object for the EntityLiving 258 */ 259 public EntitySenses getEntitySenses() 260 { 261 return this.senses; 262 } 263 264 public Random getRNG() 265 { 266 return this.rand; 267 } 268 269 public EntityLiving getAITarget() 270 { 271 return this.entityLivingToAttack; 272 } 273 274 public EntityLiving getLastAttackingEntity() 275 { 276 return this.lastAttackingEntity; 277 } 278 279 public void setLastAttackingEntity(Entity par1Entity) 280 { 281 if (par1Entity instanceof EntityLiving) 282 { 283 this.lastAttackingEntity = (EntityLiving)par1Entity; 284 } 285 } 286 287 public int getAge() 288 { 289 return this.entityAge; 290 } 291 292 public float func_70079_am() 293 { 294 return this.rotationYawHead; 295 } 296 297 @SideOnly(Side.CLIENT) 298 299 /** 300 * Sets the head's yaw rotation of the entity. 301 */ 302 public void setHeadRotationYaw(float par1) 303 { 304 this.rotationYawHead = par1; 305 } 306 307 /** 308 * the movespeed used for the new AI system 309 */ 310 public float getAIMoveSpeed() 311 { 312 return this.AIMoveSpeed; 313 } 314 315 /** 316 * set the movespeed used for the new AI system 317 */ 318 public void setAIMoveSpeed(float par1) 319 { 320 this.AIMoveSpeed = par1; 321 this.setMoveForward(par1); 322 } 323 324 public boolean attackEntityAsMob(Entity par1Entity) 325 { 326 this.setLastAttackingEntity(par1Entity); 327 return false; 328 } 329 330 /** 331 * Gets the active target the Task system uses for tracking 332 */ 333 public EntityLiving getAttackTarget() 334 { 335 return this.attackTarget; 336 } 337 338 /** 339 * Sets the active target the Task system uses for tracking 340 */ 341 public void setAttackTarget(EntityLiving par1EntityLiving) 342 { 343 this.attackTarget = par1EntityLiving; 344 ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving); 345 } 346 347 public boolean isExplosiveMob(Class par1Class) 348 { 349 return EntityCreeper.class != par1Class && EntityGhast.class != par1Class; 350 } 351 352 /** 353 * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This 354 * function is used in the AIEatGrass) 355 */ 356 public void eatGrassBonus() {} 357 358 /** 359 * Takes in the distance the entity has fallen this tick and whether its on the ground to update the fall distance 360 * and deal fall damage if landing on the ground. Args: distanceFallenThisTick, onGround 361 */ 362 protected void updateFallState(double par1, boolean par3) 363 { 364 if (par3 && this.fallDistance > 0.0F) 365 { 366 int var4 = MathHelper.floor_double(this.posX); 367 int var5 = MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset); 368 int var6 = MathHelper.floor_double(this.posZ); 369 int var7 = this.worldObj.getBlockId(var4, var5, var6); 370 371 if (var7 == 0 && this.worldObj.getBlockId(var4, var5 - 1, var6) == Block.fence.blockID) 372 { 373 var7 = this.worldObj.getBlockId(var4, var5 - 1, var6); 374 } 375 376 if (var7 > 0) 377 { 378 Block.blocksList[var7].onFallenUpon(this.worldObj, var4, var5, var6, this, this.fallDistance); 379 } 380 } 381 382 super.updateFallState(par1, par3); 383 } 384 385 /** 386 * Returns true if entity is within home distance from current position 387 */ 388 public boolean isWithinHomeDistanceCurrentPosition() 389 { 390 return this.isWithinHomeDistance(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)); 391 } 392 393 public boolean isWithinHomeDistance(int par1, int par2, int par3) 394 { 395 return this.maximumHomeDistance == -1.0F ? true : this.homePosition.getDistanceSquared(par1, par2, par3) < this.maximumHomeDistance * this.maximumHomeDistance; 396 } 397 398 public void setHomeArea(int par1, int par2, int par3, int par4) 399 { 400 this.homePosition.set(par1, par2, par3); 401 this.maximumHomeDistance = (float)par4; 402 } 403 404 public ChunkCoordinates getHomePosition() 405 { 406 return this.homePosition; 407 } 408 409 public float getMaximumHomeDistance() 410 { 411 return this.maximumHomeDistance; 412 } 413 414 public void detachHome() 415 { 416 this.maximumHomeDistance = -1.0F; 417 } 418 419 public boolean hasHome() 420 { 421 return this.maximumHomeDistance != -1.0F; 422 } 423 424 public void setRevengeTarget(EntityLiving par1EntityLiving) 425 { 426 this.entityLivingToAttack = par1EntityLiving; 427 this.revengeTimer = this.entityLivingToAttack != null ? 60 : 0; 428 ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving); 429 } 430 431 protected void entityInit() 432 { 433 this.dataWatcher.addObject(8, Integer.valueOf(this.field_70748_f)); 434 this.dataWatcher.addObject(9, Byte.valueOf((byte)0)); 435 } 436 437 /** 438 * returns true if the entity provided in the argument can be seen. (Raytrace) 439 */ 440 public boolean canEntityBeSeen(Entity par1Entity) 441 { 442 return this.worldObj.rayTraceBlocks(this.worldObj.func_82732_R().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ), this.worldObj.func_82732_R().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null; 443 } 444 445 @SideOnly(Side.CLIENT) 446 447 /** 448 * Returns the texture's file path as a String. 449 */ 450 public String getTexture() 451 { 452 return this.texture; 453 } 454 455 /** 456 * Returns true if other Entities should be prevented from moving through this Entity. 457 */ 458 public boolean canBeCollidedWith() 459 { 460 return !this.isDead; 461 } 462 463 /** 464 * Returns true if this entity should push and be pushed by other entities when colliding. 465 */ 466 public boolean canBePushed() 467 { 468 return !this.isDead; 469 } 470 471 public float getEyeHeight() 472 { 473 return this.height * 0.85F; 474 } 475 476 /** 477 * Get number of ticks, at least during which the living entity will be silent. 478 */ 479 public int getTalkInterval() 480 { 481 return 80; 482 } 483 484 /** 485 * Plays living's sound at its position 486 */ 487 public void playLivingSound() 488 { 489 String var1 = this.getLivingSound(); 490 491 if (var1 != null) 492 { 493 this.worldObj.playSoundAtEntity(this, var1, this.getSoundVolume(), this.getSoundPitch()); 494 } 495 } 496 497 /** 498 * Gets called every tick from main Entity class 499 */ 500 public void onEntityUpdate() 501 { 502 this.prevSwingProgress = this.swingProgress; 503 super.onEntityUpdate(); 504 this.worldObj.theProfiler.startSection("mobBaseTick"); 505 506 if (this.isEntityAlive() && this.rand.nextInt(1000) < this.livingSoundTime++) 507 { 508 this.livingSoundTime = -this.getTalkInterval(); 509 this.playLivingSound(); 510 } 511 512 if (this.isEntityAlive() && this.isEntityInsideOpaqueBlock()) 513 { 514 this.attackEntityFrom(DamageSource.inWall, 1); 515 } 516 517 if (this.isImmuneToFire() || this.worldObj.isRemote) 518 { 519 this.extinguish(); 520 } 521 522 if (this.isEntityAlive() && this.isInsideOfMaterial(Material.water) && !this.canBreatheUnderwater() && !this.activePotionsMap.containsKey(Integer.valueOf(Potion.waterBreathing.id))) 523 { 524 this.setAir(this.decreaseAirSupply(this.getAir())); 525 526 if (this.getAir() == -20) 527 { 528 this.setAir(0); 529 530 for (int var1 = 0; var1 < 8; ++var1) 531 { 532 float var2 = this.rand.nextFloat() - this.rand.nextFloat(); 533 float var3 = this.rand.nextFloat() - this.rand.nextFloat(); 534 float var4 = this.rand.nextFloat() - this.rand.nextFloat(); 535 this.worldObj.spawnParticle("bubble", this.posX + (double)var2, this.posY + (double)var3, this.posZ + (double)var4, this.motionX, this.motionY, this.motionZ); 536 } 537 538 this.attackEntityFrom(DamageSource.drown, 2); 539 } 540 541 this.extinguish(); 542 } 543 else 544 { 545 this.setAir(300); 546 } 547 548 this.prevCameraPitch = this.cameraPitch; 549 550 if (this.attackTime > 0) 551 { 552 --this.attackTime; 553 } 554 555 if (this.hurtTime > 0) 556 { 557 --this.hurtTime; 558 } 559 560 if (this.hurtResistantTime > 0) 561 { 562 --this.hurtResistantTime; 563 } 564 565 if (this.health <= 0) 566 { 567 this.onDeathUpdate(); 568 } 569 570 if (this.recentlyHit > 0) 571 { 572 --this.recentlyHit; 573 } 574 else 575 { 576 this.attackingPlayer = null; 577 } 578 579 if (this.lastAttackingEntity != null && !this.lastAttackingEntity.isEntityAlive()) 580 { 581 this.lastAttackingEntity = null; 582 } 583 584 if (this.entityLivingToAttack != null) 585 { 586 if (!this.entityLivingToAttack.isEntityAlive()) 587 { 588 this.setRevengeTarget((EntityLiving)null); 589 } 590 else if (this.revengeTimer > 0) 591 { 592 --this.revengeTimer; 593 } 594 else 595 { 596 this.setRevengeTarget((EntityLiving)null); 597 } 598 } 599 600 this.updatePotionEffects(); 601 this.field_70763_ax = this.field_70764_aw; 602 this.prevRenderYawOffset = this.renderYawOffset; 603 this.prevRotationYawHead = this.rotationYawHead; 604 this.prevRotationYaw = this.rotationYaw; 605 this.prevRotationPitch = this.rotationPitch; 606 this.worldObj.theProfiler.endSection(); 607 } 608 609 /** 610 * handles entity death timer, experience orb and particle creation 611 */ 612 protected void onDeathUpdate() 613 { 614 ++this.deathTime; 615 616 if (this.deathTime == 20) 617 { 618 int var1; 619 620 if (!this.worldObj.isRemote && (this.recentlyHit > 0 || this.isPlayer()) && !this.isChild()) 621 { 622 var1 = this.getExperiencePoints(this.attackingPlayer); 623 624 while (var1 > 0) 625 { 626 int var2 = EntityXPOrb.getXPSplit(var1); 627 var1 -= var2; 628 this.worldObj.spawnEntityInWorld(new EntityXPOrb(this.worldObj, this.posX, this.posY, this.posZ, var2)); 629 } 630 } 631 632 this.setDead(); 633 634 for (var1 = 0; var1 < 20; ++var1) 635 { 636 double var8 = this.rand.nextGaussian() * 0.02D; 637 double var4 = this.rand.nextGaussian() * 0.02D; 638 double var6 = this.rand.nextGaussian() * 0.02D; 639 this.worldObj.spawnParticle("explode", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var8, var4, var6); 640 } 641 } 642 } 643 644 /** 645 * Decrements the entity's air supply when underwater 646 */ 647 protected int decreaseAirSupply(int par1) 648 { 649 int var2 = EnchantmentHelper.getRespiration(this); 650 return var2 > 0 && this.rand.nextInt(var2 + 1) > 0 ? par1 : par1 - 1; 651 } 652 653 /** 654 * Get the experience points the entity currently has. 655 */ 656 protected int getExperiencePoints(EntityPlayer par1EntityPlayer) 657 { 658 return this.experienceValue; 659 } 660 661 /** 662 * Only use is to identify if class is an instance of player for experience dropping 663 */ 664 protected boolean isPlayer() 665 { 666 return false; 667 } 668 669 /** 670 * Spawns an explosion particle around the Entity's location 671 */ 672 public void spawnExplosionParticle() 673 { 674 for (int var1 = 0; var1 < 20; ++var1) 675 { 676 double var2 = this.rand.nextGaussian() * 0.02D; 677 double var4 = this.rand.nextGaussian() * 0.02D; 678 double var6 = this.rand.nextGaussian() * 0.02D; 679 double var8 = 10.0D; 680 this.worldObj.spawnParticle("explode", this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width - var2 * var8, this.posY + (double)(this.rand.nextFloat() * this.height) - var4 * var8, this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width - var6 * var8, var2, var4, var6); 681 } 682 } 683 684 /** 685 * Handles updating while being ridden by an entity 686 */ 687 public void updateRidden() 688 { 689 super.updateRidden(); 690 this.field_70768_au = this.field_70766_av; 691 this.field_70766_av = 0.0F; 692 this.fallDistance = 0.0F; 693 } 694 695 @SideOnly(Side.CLIENT) 696 697 /** 698 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX, 699 * posY, posZ, yaw, pitch 700 */ 701 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9) 702 { 703 this.yOffset = 0.0F; 704 this.newPosX = par1; 705 this.newPosY = par3; 706 this.newPosZ = par5; 707 this.newRotationYaw = (double)par7; 708 this.newRotationPitch = (double)par8; 709 this.newPosRotationIncrements = par9; 710 } 711 712 /** 713 * Called to update the entity's position/logic. 714 */ 715 public void onUpdate() 716 { 717 if (ForgeHooks.onLivingUpdate(this)) 718 { 719 return; 720 } 721 722 super.onUpdate(); 723 724 if (!this.worldObj.isRemote) 725 { 726 for (int var1 = 0; var1 < 5; ++var1) 727 { 728 ItemStack var2 = this.getCurrentItemOrArmor(var1); 729 730 if (!ItemStack.areItemStacksEqual(var2, this.field_82180_bT[var1])) 731 { 732 ((WorldServer)this.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, new Packet5PlayerInventory(this.entityId, var1, var2)); 733 this.field_82180_bT[var1] = var2 == null ? null : var2.copy(); 734 } 735 } 736 } 737 738 if (this.arrowHitTempCounter > 0) 739 { 740 if (this.arrowHitTimer <= 0) 741 { 742 this.arrowHitTimer = 60; 743 } 744 745 --this.arrowHitTimer; 746 747 if (this.arrowHitTimer <= 0) 748 { 749 --this.arrowHitTempCounter; 750 } 751 } 752 753 this.onLivingUpdate(); 754 double var12 = this.posX - this.prevPosX; 755 double var3 = this.posZ - this.prevPosZ; 756 float var5 = (float)(var12 * var12 + var3 * var3); 757 float var6 = this.renderYawOffset; 758 float var7 = 0.0F; 759 this.field_70768_au = this.field_70766_av; 760 float var8 = 0.0F; 761 762 if (var5 > 0.0025000002F) 763 { 764 var8 = 1.0F; 765 var7 = (float)Math.sqrt((double)var5) * 3.0F; 766 var6 = (float)Math.atan2(var3, var12) * 180.0F / (float)Math.PI - 90.0F; 767 } 768 769 if (this.swingProgress > 0.0F) 770 { 771 var6 = this.rotationYaw; 772 } 773 774 if (!this.onGround) 775 { 776 var8 = 0.0F; 777 } 778 779 this.field_70766_av += (var8 - this.field_70766_av) * 0.3F; 780 this.worldObj.theProfiler.startSection("headTurn"); 781 782 if (this.isAIEnabled()) 783 { 784 this.bodyHelper.func_75664_a(); 785 } 786 else 787 { 788 float var9 = MathHelper.wrapAngleTo180_float(var6 - this.renderYawOffset); 789 this.renderYawOffset += var9 * 0.3F; 790 float var10 = MathHelper.wrapAngleTo180_float(this.rotationYaw - this.renderYawOffset); 791 boolean var11 = var10 < -90.0F || var10 >= 90.0F; 792 793 if (var10 < -75.0F) 794 { 795 var10 = -75.0F; 796 } 797 798 if (var10 >= 75.0F) 799 { 800 var10 = 75.0F; 801 } 802 803 this.renderYawOffset = this.rotationYaw - var10; 804 805 if (var10 * var10 > 2500.0F) 806 { 807 this.renderYawOffset += var10 * 0.2F; 808 } 809 810 if (var11) 811 { 812 var7 *= -1.0F; 813 } 814 } 815 816 this.worldObj.theProfiler.endSection(); 817 this.worldObj.theProfiler.startSection("rangeChecks"); 818 819 while (this.rotationYaw - this.prevRotationYaw < -180.0F) 820 { 821 this.prevRotationYaw -= 360.0F; 822 } 823 824 while (this.rotationYaw - this.prevRotationYaw >= 180.0F) 825 { 826 this.prevRotationYaw += 360.0F; 827 } 828 829 while (this.renderYawOffset - this.prevRenderYawOffset < -180.0F) 830 { 831 this.prevRenderYawOffset -= 360.0F; 832 } 833 834 while (this.renderYawOffset - this.prevRenderYawOffset >= 180.0F) 835 { 836 this.prevRenderYawOffset += 360.0F; 837 } 838 839 while (this.rotationPitch - this.prevRotationPitch < -180.0F) 840 { 841 this.prevRotationPitch -= 360.0F; 842 } 843 844 while (this.rotationPitch - this.prevRotationPitch >= 180.0F) 845 { 846 this.prevRotationPitch += 360.0F; 847 } 848 849 while (this.rotationYawHead - this.prevRotationYawHead < -180.0F) 850 { 851 this.prevRotationYawHead -= 360.0F; 852 } 853 854 while (this.rotationYawHead - this.prevRotationYawHead >= 180.0F) 855 { 856 this.prevRotationYawHead += 360.0F; 857 } 858 859 this.worldObj.theProfiler.endSection(); 860 this.field_70764_aw += var7; 861 } 862 863 /** 864 * Heal living entity (param: amount of half-hearts) 865 */ 866 public void heal(int par1) 867 { 868 if (this.health > 0) 869 { 870 this.health += par1; 871 872 if (this.health > this.getMaxHealth()) 873 { 874 this.health = this.getMaxHealth(); 875 } 876 877 this.hurtResistantTime = this.maxHurtResistantTime / 2; 878 } 879 } 880 881 public abstract int getMaxHealth(); 882 883 public int getHealth() 884 { 885 return this.health; 886 } 887 888 public void setEntityHealth(int par1) 889 { 890 this.health = par1; 891 892 if (par1 > this.getMaxHealth()) 893 { 894 par1 = this.getMaxHealth(); 895 } 896 } 897 898 /** 899 * Called when the entity is attacked. 900 */ 901 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 902 { 903 if (ForgeHooks.onLivingAttack(this, par1DamageSource, par2)) 904 { 905 return false; 906 } 907 908 if (this.worldObj.isRemote) 909 { 910 return false; 911 } 912 else 913 { 914 this.entityAge = 0; 915 916 if (this.health <= 0) 917 { 918 return false; 919 } 920 else if (par1DamageSource.fireDamage() && this.isPotionActive(Potion.fireResistance)) 921 { 922 return false; 923 } 924 else 925 { 926 if ((par1DamageSource == DamageSource.field_82728_o || par1DamageSource == DamageSource.field_82729_p) && this.getCurrentItemOrArmor(4) != null) 927 { 928 par2 = (int)((float)par2 * 0.55F); 929 } 930 931 this.legYaw = 1.5F; 932 boolean var3 = true; 933 934 if ((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F) 935 { 936 if (par2 <= this.lastDamage) 937 { 938 return false; 939 } 940 941 this.damageEntity(par1DamageSource, par2 - this.lastDamage); 942 this.lastDamage = par2; 943 var3 = false; 944 } 945 else 946 { 947 this.lastDamage = par2; 948 this.prevHealth = this.health; 949 this.hurtResistantTime = this.maxHurtResistantTime; 950 this.damageEntity(par1DamageSource, par2); 951 this.hurtTime = this.maxHurtTime = 10; 952 } 953 954 this.attackedAtYaw = 0.0F; 955 Entity var4 = par1DamageSource.getEntity(); 956 957 if (var4 != null) 958 { 959 if (var4 instanceof EntityLiving) 960 { 961 this.setRevengeTarget((EntityLiving)var4); 962 } 963 964 if (var4 instanceof EntityPlayer) 965 { 966 this.recentlyHit = 60; 967 this.attackingPlayer = (EntityPlayer)var4; 968 } 969 else if (var4 instanceof EntityWolf) 970 { 971 EntityWolf var5 = (EntityWolf)var4; 972 973 if (var5.isTamed()) 974 { 975 this.recentlyHit = 60; 976 this.attackingPlayer = null; 977 } 978 } 979 } 980 981 if (var3) 982 { 983 this.worldObj.setEntityState(this, (byte)2); 984 985 if (par1DamageSource != DamageSource.drown && par1DamageSource != DamageSource.field_76375_l) 986 { 987 this.setBeenAttacked(); 988 } 989 990 if (var4 != null) 991 { 992 double var9 = var4.posX - this.posX; 993 double var7; 994 995 for (var7 = var4.posZ - this.posZ; var9 * var9 + var7 * var7 < 1.0E-4D; var7 = (Math.random() - Math.random()) * 0.01D) 996 { 997 var9 = (Math.random() - Math.random()) * 0.01D; 998 } 999 1000 this.attackedAtYaw = (float)(Math.atan2(var7, var9) * 180.0D / Math.PI) - this.rotationYaw; 1001 this.knockBack(var4, par2, var9, var7); 1002 } 1003 else 1004 { 1005 this.attackedAtYaw = (float)((int)(Math.random() * 2.0D) * 180); 1006 } 1007 } 1008 1009 if (this.health <= 0) 1010 { 1011 if (var3) 1012 { 1013 this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), this.getSoundPitch()); 1014 } 1015 1016 this.onDeath(par1DamageSource); 1017 } 1018 else if (var3) 1019 { 1020 this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), this.getSoundPitch()); 1021 } 1022 1023 return true; 1024 } 1025 } 1026 } 1027 1028 /** 1029 * Gets the pitch of living sounds in living entities. 1030 */ 1031 private float getSoundPitch() 1032 { 1033 return this.isChild() ? (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.5F : (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F; 1034 } 1035 1036 @SideOnly(Side.CLIENT) 1037 1038 /** 1039 * Setups the entity to do the hurt animation. Only used by packets in multiplayer. 1040 */ 1041 public void performHurtAnimation() 1042 { 1043 this.hurtTime = this.maxHurtTime = 10; 1044 this.attackedAtYaw = 0.0F; 1045 } 1046 1047 /** 1048 * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue 1049 */ 1050 public int getTotalArmorValue() 1051 { 1052 int var1 = 0; 1053 ItemStack[] var2 = this.getLastActiveItems(); 1054 int var3 = var2.length; 1055 1056 for (int var4 = 0; var4 < var3; ++var4) 1057 { 1058 ItemStack var5 = var2[var4]; 1059 1060 if (var5 != null && var5.getItem() instanceof ItemArmor) 1061 { 1062 int var6 = ((ItemArmor)var5.getItem()).damageReduceAmount; 1063 var1 += var6; 1064 } 1065 } 1066 1067 return var1; 1068 } 1069 1070 protected void damageArmor(int par1) {} 1071 1072 /** 1073 * Reduces damage, depending on armor 1074 */ 1075 protected int applyArmorCalculations(DamageSource par1DamageSource, int par2) 1076 { 1077 if (!par1DamageSource.isUnblockable()) 1078 { 1079 int var3 = 25 - this.getTotalArmorValue(); 1080 int var4 = par2 * var3 + this.carryoverDamage; 1081 this.damageArmor(par2); 1082 par2 = var4 / 25; 1083 this.carryoverDamage = var4 % 25; 1084 } 1085 1086 return par2; 1087 } 1088 1089 /** 1090 * Reduces damage, depending on potions 1091 */ 1092 protected int applyPotionDamageCalculations(DamageSource par1DamageSource, int par2) 1093 { 1094 if (this.isPotionActive(Potion.resistance)) 1095 { 1096 int var3 = (this.getActivePotionEffect(Potion.resistance).getAmplifier() + 1) * 5; 1097 int var4 = 25 - var3; 1098 int var5 = par2 * var4 + this.carryoverDamage; 1099 par2 = var5 / 25; 1100 this.carryoverDamage = var5 % 25; 1101 } 1102 1103 return par2; 1104 } 1105 1106 /** 1107 * Deals damage to the entity. If its a EntityPlayer then will take damage from the armor first and then health 1108 * second with the reduced value. Args: damageAmount 1109 */ 1110 protected void damageEntity(DamageSource par1DamageSource, int par2) 1111 { 1112 if (!this.field_83001_bt) 1113 { 1114 par2 = ForgeHooks.onLivingHurt(this, par1DamageSource, par2); 1115 if (par2 <= 0) 1116 { 1117 return; 1118 } 1119 par2 = this.applyArmorCalculations(par1DamageSource, par2); 1120 par2 = this.applyPotionDamageCalculations(par1DamageSource, par2); 1121 this.health -= par2; 1122 } 1123 } 1124 1125 /** 1126 * Returns the volume for the sounds this mob makes. 1127 */ 1128 protected float getSoundVolume() 1129 { 1130 return 1.0F; 1131 } 1132 1133 /** 1134 * Returns the sound this mob makes while it's alive. 1135 */ 1136 protected String getLivingSound() 1137 { 1138 return null; 1139 } 1140 1141 /** 1142 * Returns the sound this mob makes when it is hurt. 1143 */ 1144 protected String getHurtSound() 1145 { 1146 return "damage.hit"; 1147 } 1148 1149 /** 1150 * Returns the sound this mob makes on death. 1151 */ 1152 protected String getDeathSound() 1153 { 1154 return "damage.hit"; 1155 } 1156 1157 /** 1158 * knocks back this entity 1159 */ 1160 public void knockBack(Entity par1Entity, int par2, double par3, double par5) 1161 { 1162 this.isAirBorne = true; 1163 float var7 = MathHelper.sqrt_double(par3 * par3 + par5 * par5); 1164 float var8 = 0.4F; 1165 this.motionX /= 2.0D; 1166 this.motionY /= 2.0D; 1167 this.motionZ /= 2.0D; 1168 this.motionX -= par3 / (double)var7 * (double)var8; 1169 this.motionY += (double)var8; 1170 this.motionZ -= par5 / (double)var7 * (double)var8; 1171 1172 if (this.motionY > 0.4000000059604645D) 1173 { 1174 this.motionY = 0.4000000059604645D; 1175 } 1176 } 1177 1178 /** 1179 * Called when the mob's health reaches 0. 1180 */ 1181 public void onDeath(DamageSource par1DamageSource) 1182 { 1183 if (ForgeHooks.onLivingDeath(this, par1DamageSource)) 1184 { 1185 return; 1186 } 1187 1188 Entity var2 = par1DamageSource.getEntity(); 1189 1190 if (this.scoreValue >= 0 && var2 != null) 1191 { 1192 var2.addToPlayerScore(this, this.scoreValue); 1193 } 1194 1195 if (var2 != null) 1196 { 1197 var2.onKillEntity(this); 1198 } 1199 1200 this.dead = true; 1201 1202 if (!this.worldObj.isRemote) 1203 { 1204 int var3 = 0; 1205 1206 if (var2 instanceof EntityPlayer) 1207 { 1208 var3 = EnchantmentHelper.getLootingModifier((EntityLiving)var2); 1209 } 1210 1211 captureDrops = true; 1212 capturedDrops.clear(); 1213 int var4 = 0; 1214 1215 if (!this.isChild() && this.worldObj.func_82736_K().func_82766_b("doMobLoot")) 1216 { 1217 this.dropFewItems(this.recentlyHit > 0, var3); 1218 this.func_82160_b(this.recentlyHit > 0, var3); 1219 1220 if (this.recentlyHit > 0) 1221 { 1222 var4 = this.rand.nextInt(200) - var3; 1223 1224 if (var4 < 5) 1225 { 1226 this.dropRareDrop(var4 <= 0 ? 1 : 0); 1227 } 1228 } 1229 } 1230 1231 captureDrops = false; 1232 1233 if (!ForgeHooks.onLivingDrops(this, par1DamageSource, capturedDrops, var3, recentlyHit > 0, var4)) 1234 { 1235 for (EntityItem item : capturedDrops) 1236 { 1237 worldObj.spawnEntityInWorld(item); 1238 } 1239 } 1240 } 1241 1242 this.worldObj.setEntityState(this, (byte)3); 1243 } 1244 1245 protected void dropRareDrop(int par1) {} 1246 1247 /** 1248 * Drop 0-2 items of this living's type 1249 */ 1250 protected void dropFewItems(boolean par1, int par2) 1251 { 1252 int var3 = this.getDropItemId(); 1253 1254 if (var3 > 0) 1255 { 1256 int var4 = this.rand.nextInt(3); 1257 1258 if (par2 > 0) 1259 { 1260 var4 += this.rand.nextInt(par2 + 1); 1261 } 1262 1263 for (int var5 = 0; var5 < var4; ++var5) 1264 { 1265 this.dropItem(var3, 1); 1266 } 1267 } 1268 } 1269 1270 /** 1271 * Returns the item ID for the item the mob drops on death. 1272 */ 1273 protected int getDropItemId() 1274 { 1275 return 0; 1276 } 1277 1278 /** 1279 * Called when the mob is falling. Calculates and applies fall damage. 1280 */ 1281 protected void fall(float par1) 1282 { 1283 par1 = ForgeHooks.onLivingFall(this, par1); 1284 if (par1 <= 0) 1285 { 1286 return; 1287 } 1288 1289 super.fall(par1); 1290 int var2 = MathHelper.ceiling_float_int(par1 - 3.0F); 1291 1292 if (var2 > 0) 1293 { 1294 if (var2 > 4) 1295 { 1296 this.worldObj.playSoundAtEntity(this, "damage.fallbig", 1.0F, 1.0F); 1297 } 1298 else 1299 { 1300 this.worldObj.playSoundAtEntity(this, "damage.fallsmall", 1.0F, 1.0F); 1301 } 1302 1303 this.attackEntityFrom(DamageSource.fall, var2); 1304 int var3 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY - 0.20000000298023224D - (double)this.yOffset), MathHelper.floor_double(this.posZ)); 1305 1306 if (var3 > 0) 1307 { 1308 StepSound var4 = Block.blocksList[var3].stepSound; 1309 this.worldObj.playSoundAtEntity(this, var4.getStepSound(), var4.getVolume() * 0.5F, var4.getPitch() * 0.75F); 1310 } 1311 } 1312 } 1313 1314 /** 1315 * Moves the entity based on the specified heading. Args: strafe, forward 1316 */ 1317 public void moveEntityWithHeading(float par1, float par2) 1318 { 1319 double var9; 1320 1321 if (this.isInWater() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying)) 1322 { 1323 var9 = this.posY; 1324 this.moveFlying(par1, par2, this.isAIEnabled() ? 0.04F : 0.02F); 1325 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1326 this.motionX *= 0.800000011920929D; 1327 this.motionY *= 0.800000011920929D; 1328 this.motionZ *= 0.800000011920929D; 1329 this.motionY -= 0.02D; 1330 1331 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ)) 1332 { 1333 this.motionY = 0.30000001192092896D; 1334 } 1335 } 1336 else if (this.handleLavaMovement() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying)) 1337 { 1338 var9 = this.posY; 1339 this.moveFlying(par1, par2, 0.02F); 1340 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1341 this.motionX *= 0.5D; 1342 this.motionY *= 0.5D; 1343 this.motionZ *= 0.5D; 1344 this.motionY -= 0.02D; 1345 1346 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ)) 1347 { 1348 this.motionY = 0.30000001192092896D; 1349 } 1350 } 1351 else 1352 { 1353 float var3 = 0.91F; 1354 1355 if (this.onGround) 1356 { 1357 var3 = 0.54600006F; 1358 int var4 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ)); 1359 1360 if (var4 > 0) 1361 { 1362 var3 = Block.blocksList[var4].slipperiness * 0.91F; 1363 } 1364 } 1365 1366 float var8 = 0.16277136F / (var3 * var3 * var3); 1367 float var5; 1368 1369 if (this.onGround) 1370 { 1371 if (this.isAIEnabled()) 1372 { 1373 var5 = this.getAIMoveSpeed(); 1374 } 1375 else 1376 { 1377 var5 = this.landMovementFactor; 1378 } 1379 1380 var5 *= var8; 1381 } 1382 else 1383 { 1384 var5 = this.jumpMovementFactor; 1385 } 1386 1387 this.moveFlying(par1, par2, var5); 1388 var3 = 0.91F; 1389 1390 if (this.onGround) 1391 { 1392 var3 = 0.54600006F; 1393 int var6 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ)); 1394 1395 if (var6 > 0) 1396 { 1397 var3 = Block.blocksList[var6].slipperiness * 0.91F; 1398 } 1399 } 1400 1401 if (this.isOnLadder()) 1402 { 1403 float var10 = 0.15F; 1404 1405 if (this.motionX < (double)(-var10)) 1406 { 1407 this.motionX = (double)(-var10); 1408 } 1409 1410 if (this.motionX > (double)var10) 1411 { 1412 this.motionX = (double)var10; 1413 } 1414 1415 if (this.motionZ < (double)(-var10)) 1416 { 1417 this.motionZ = (double)(-var10); 1418 } 1419 1420 if (this.motionZ > (double)var10) 1421 { 1422 this.motionZ = (double)var10; 1423 } 1424 1425 this.fallDistance = 0.0F; 1426 1427 if (this.motionY < -0.15D) 1428 { 1429 this.motionY = -0.15D; 1430 } 1431 1432 boolean var7 = this.isSneaking() && this instanceof EntityPlayer; 1433 1434 if (var7 && this.motionY < 0.0D) 1435 { 1436 this.motionY = 0.0D; 1437 } 1438 } 1439 1440 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1441 1442 if (this.isCollidedHorizontally && this.isOnLadder()) 1443 { 1444 this.motionY = 0.2D; 1445 } 1446 1447 this.motionY -= 0.08D; 1448 this.motionY *= 0.9800000190734863D; 1449 this.motionX *= (double)var3; 1450 this.motionZ *= (double)var3; 1451 } 1452 1453 this.prevLegYaw = this.legYaw; 1454 var9 = this.posX - this.prevPosX; 1455 double var12 = this.posZ - this.prevPosZ; 1456 float var11 = MathHelper.sqrt_double(var9 * var9 + var12 * var12) * 4.0F; 1457 1458 if (var11 > 1.0F) 1459 { 1460 var11 = 1.0F; 1461 } 1462 1463 this.legYaw += (var11 - this.legYaw) * 0.4F; 1464 this.legSwing += this.legYaw; 1465 } 1466 1467 /** 1468 * returns true if this entity is by a ladder, false otherwise 1469 */ 1470 public boolean isOnLadder() 1471 { 1472 int var1 = MathHelper.floor_double(this.posX); 1473 int var2 = MathHelper.floor_double(this.boundingBox.minY); 1474 int var3 = MathHelper.floor_double(this.posZ); 1475 int var4 = this.worldObj.getBlockId(var1, var2, var3); 1476 return ForgeHooks.isLivingOnLadder(Block.blocksList[var4], worldObj, var1, var2, var3); 1477 } 1478 1479 /** 1480 * (abstract) Protected helper method to write subclass entity data to NBT. 1481 */ 1482 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 1483 { 1484 par1NBTTagCompound.setShort("Health", (short)this.health); 1485 par1NBTTagCompound.setShort("HurtTime", (short)this.hurtTime); 1486 par1NBTTagCompound.setShort("DeathTime", (short)this.deathTime); 1487 par1NBTTagCompound.setShort("AttackTime", (short)this.attackTime); 1488 par1NBTTagCompound.setBoolean("CanPickUpLoot", this.field_82172_bs); 1489 par1NBTTagCompound.setBoolean("PersistenceRequired", this.field_82179_bU); 1490 par1NBTTagCompound.setBoolean("Invulnerable", this.field_83001_bt); 1491 NBTTagList var2 = new NBTTagList(); 1492 1493 for (int var3 = 0; var3 < this.field_82182_bS.length; ++var3) 1494 { 1495 NBTTagCompound var4 = new NBTTagCompound(); 1496 1497 if (this.field_82182_bS[var3] != null) 1498 { 1499 this.field_82182_bS[var3].writeToNBT(var4); 1500 } 1501 1502 var2.appendTag(var4); 1503 } 1504 1505 par1NBTTagCompound.setTag("Equipment", var2); 1506 NBTTagList var6; 1507 1508 if (!this.activePotionsMap.isEmpty()) 1509 { 1510 var6 = new NBTTagList(); 1511 Iterator var7 = this.activePotionsMap.values().iterator(); 1512 1513 while (var7.hasNext()) 1514 { 1515 PotionEffect var5 = (PotionEffect)var7.next(); 1516 var6.appendTag(var5.func_82719_a(new NBTTagCompound())); 1517 } 1518 1519 par1NBTTagCompound.setTag("ActiveEffects", var6); 1520 } 1521 1522 var6 = new NBTTagList(); 1523 1524 for (int var8 = 0; var8 < this.field_82174_bp.length; ++var8) 1525 { 1526 var6.appendTag(new NBTTagFloat(var8 + "", this.field_82174_bp[var8])); 1527 } 1528 1529 par1NBTTagCompound.setTag("DropChances", var6); 1530 } 1531 1532 /** 1533 * (abstract) Protected helper method to read subclass entity data from NBT. 1534 */ 1535 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 1536 { 1537 if (this.health < -32768) 1538 { 1539 this.health = -32768; 1540 } 1541 1542 this.health = par1NBTTagCompound.getShort("Health"); 1543 1544 if (!par1NBTTagCompound.hasKey("Health")) 1545 { 1546 this.health = this.getMaxHealth(); 1547 } 1548 1549 this.hurtTime = par1NBTTagCompound.getShort("HurtTime"); 1550 this.deathTime = par1NBTTagCompound.getShort("DeathTime"); 1551 this.attackTime = par1NBTTagCompound.getShort("AttackTime"); 1552 this.field_82172_bs = par1NBTTagCompound.getBoolean("CanPickUpLoot"); 1553 this.field_82179_bU = par1NBTTagCompound.getBoolean("PersistenceRequired"); 1554 this.field_83001_bt = par1NBTTagCompound.getBoolean("Invulnerable"); 1555 NBTTagList var2; 1556 int var3; 1557 1558 if (par1NBTTagCompound.hasKey("Equipment")) 1559 { 1560 var2 = par1NBTTagCompound.getTagList("Equipment"); 1561 1562 for (var3 = 0; var3 < this.field_82182_bS.length; ++var3) 1563 { 1564 this.field_82182_bS[var3] = ItemStack.loadItemStackFromNBT((NBTTagCompound)var2.tagAt(var3)); 1565 } 1566 } 1567 1568 if (par1NBTTagCompound.hasKey("ActiveEffects")) 1569 { 1570 var2 = par1NBTTagCompound.getTagList("ActiveEffects"); 1571 1572 for (var3 = 0; var3 < var2.tagCount(); ++var3) 1573 { 1574 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3); 1575 PotionEffect var5 = PotionEffect.func_82722_b(var4); 1576 this.activePotionsMap.put(Integer.valueOf(var5.getPotionID()), var5); 1577 } 1578 } 1579 1580 if (par1NBTTagCompound.hasKey("DropChances")) 1581 { 1582 var2 = par1NBTTagCompound.getTagList("DropChances"); 1583 1584 for (var3 = 0; var3 < var2.tagCount(); ++var3) 1585 { 1586 this.field_82174_bp[var3] = ((NBTTagFloat)var2.tagAt(var3)).data; 1587 } 1588 } 1589 } 1590 1591 /** 1592 * Checks whether target entity is alive. 1593 */ 1594 public boolean isEntityAlive() 1595 { 1596 return !this.isDead && this.health > 0; 1597 } 1598 1599 public boolean canBreatheUnderwater() 1600 { 1601 return false; 1602 } 1603 1604 public void setMoveForward(float par1) 1605 { 1606 this.moveForward = par1; 1607 } 1608 1609 public void setJumping(boolean par1) 1610 { 1611 this.isJumping = par1; 1612 } 1613 1614 /** 1615 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 1616 * use this to react to sunlight and start to burn. 1617 */ 1618 public void onLivingUpdate() 1619 { 1620 if (this.jumpTicks > 0) 1621 { 1622 --this.jumpTicks; 1623 } 1624 1625 if (this.newPosRotationIncrements > 0) 1626 { 1627 double var1 = this.posX + (this.newPosX - this.posX) / (double)this.newPosRotationIncrements; 1628 double var3 = this.posY + (this.newPosY - this.posY) / (double)this.newPosRotationIncrements; 1629 double var5 = this.posZ + (this.newPosZ - this.posZ) / (double)this.newPosRotationIncrements; 1630 double var7 = MathHelper.wrapAngleTo180_double(this.newRotationYaw - (double)this.rotationYaw); 1631 this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.newPosRotationIncrements); 1632 this.rotationPitch = (float)((double)this.rotationPitch + (this.newRotationPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements); 1633 --this.newPosRotationIncrements; 1634 this.setPosition(var1, var3, var5); 1635 this.setRotation(this.rotationYaw, this.rotationPitch); 1636 } 1637 1638 if (Math.abs(this.motionX) < 0.005D) 1639 { 1640 this.motionX = 0.0D; 1641 } 1642 1643 if (Math.abs(this.motionY) < 0.005D) 1644 { 1645 this.motionY = 0.0D; 1646 } 1647 1648 if (Math.abs(this.motionZ) < 0.005D) 1649 { 1650 this.motionZ = 0.0D; 1651 } 1652 1653 this.worldObj.theProfiler.startSection("ai"); 1654 1655 if (this.isMovementBlocked()) 1656 { 1657 this.isJumping = false; 1658 this.moveStrafing = 0.0F; 1659 this.moveForward = 0.0F; 1660 this.randomYawVelocity = 0.0F; 1661 } 1662 else if (this.isClientWorld()) 1663 { 1664 if (this.isAIEnabled()) 1665 { 1666 this.worldObj.theProfiler.startSection("newAi"); 1667 this.updateAITasks(); 1668 this.worldObj.theProfiler.endSection(); 1669 } 1670 else 1671 { 1672 this.worldObj.theProfiler.startSection("oldAi"); 1673 this.updateEntityActionState(); 1674 this.worldObj.theProfiler.endSection(); 1675 this.rotationYawHead = this.rotationYaw; 1676 } 1677 } 1678 1679 this.worldObj.theProfiler.endSection(); 1680 this.worldObj.theProfiler.startSection("jump"); 1681 1682 if (this.isJumping) 1683 { 1684 if (!this.isInWater() && !this.handleLavaMovement()) 1685 { 1686 if (this.onGround && this.jumpTicks == 0) 1687 { 1688 this.jump(); 1689 this.jumpTicks = 10; 1690 } 1691 } 1692 else 1693 { 1694 this.motionY += 0.03999999910593033D; 1695 } 1696 } 1697 else 1698 { 1699 this.jumpTicks = 0; 1700 } 1701 1702 this.worldObj.theProfiler.endSection(); 1703 this.worldObj.theProfiler.startSection("travel"); 1704 this.moveStrafing *= 0.98F; 1705 this.moveForward *= 0.98F; 1706 this.randomYawVelocity *= 0.9F; 1707 float var11 = this.landMovementFactor; 1708 this.landMovementFactor *= this.getSpeedModifier(); 1709 this.moveEntityWithHeading(this.moveStrafing, this.moveForward); 1710 this.landMovementFactor = var11; 1711 this.worldObj.theProfiler.endSection(); 1712 this.worldObj.theProfiler.startSection("push"); 1713 List var2; 1714 Iterator var12; 1715 1716 if (!this.worldObj.isRemote) 1717 { 1718 var2 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D)); 1719 1720 if (var2 != null && !var2.isEmpty()) 1721 { 1722 var12 = var2.iterator(); 1723 1724 while (var12.hasNext()) 1725 { 1726 Entity var4 = (Entity)var12.next(); 1727 1728 if (var4.canBePushed()) 1729 { 1730 this.func_82167_n(var4); 1731 } 1732 } 1733 } 1734 } 1735 1736 this.worldObj.theProfiler.endSection(); 1737 this.worldObj.theProfiler.startSection("looting"); 1738 1739 if (!this.worldObj.isRemote && this.field_82172_bs && this.worldObj.func_82736_K().func_82766_b("mobGriefing")) 1740 { 1741 var2 = this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.boundingBox.expand(1.0D, 0.0D, 1.0D)); 1742 var12 = var2.iterator(); 1743 1744 while (var12.hasNext()) 1745 { 1746 EntityItem var13 = (EntityItem)var12.next(); 1747 1748 if (!var13.isDead && var13.item != null) 1749 { 1750 ItemStack var14 = var13.item; 1751 int var6 = func_82159_b(var14); 1752 1753 if (var6 > -1) 1754 { 1755 boolean var15 = true; 1756 ItemStack var8 = this.getCurrentItemOrArmor(var6); 1757 1758 if (var8 != null) 1759 { 1760 if (var6 == 0) 1761 { 1762 if (var14.getItem() instanceof ItemSword && !(var8.getItem() instanceof ItemSword)) 1763 { 1764 var15 = true; 1765 } 1766 else if (var14.getItem() instanceof ItemSword && var8.getItem() instanceof ItemSword) 1767 { 1768 ItemSword var9 = (ItemSword)var14.getItem(); 1769 ItemSword var10 = (ItemSword)var8.getItem(); 1770 1771 if (var9.func_82803_g() == var10.func_82803_g()) 1772 { 1773 var15 = var14.getItemDamage() > var8.getItemDamage() || var14.hasTagCompound() && !var8.hasTagCompound(); 1774 } 1775 else 1776 { 1777 var15 = var9.func_82803_g() > var10.func_82803_g(); 1778 } 1779 } 1780 else 1781 { 1782 var15 = false; 1783 } 1784 } 1785 else if (var14.getItem() instanceof ItemArmor && !(var8.getItem() instanceof ItemArmor)) 1786 { 1787 var15 = true; 1788 } 1789 else if (var14.getItem() instanceof ItemArmor && var8.getItem() instanceof ItemArmor) 1790 { 1791 ItemArmor var16 = (ItemArmor)var14.getItem(); 1792 ItemArmor var17 = (ItemArmor)var8.getItem(); 1793 1794 if (var16.damageReduceAmount == var17.damageReduceAmount) 1795 { 1796 var15 = var14.getItemDamage() > var8.getItemDamage() || var14.hasTagCompound() && !var8.hasTagCompound(); 1797 } 1798 else 1799 { 1800 var15 = var16.damageReduceAmount > var17.damageReduceAmount; 1801 } 1802 } 1803 else 1804 { 1805 var15 = false; 1806 } 1807 } 1808 1809 if (var15) 1810 { 1811 if (var8 != null && this.rand.nextFloat() - 0.1F < this.field_82174_bp[var6]) 1812 { 1813 this.entityDropItem(var8, 0.0F); 1814 } 1815 1816 this.func_70062_b(var6, var14); 1817 this.field_82174_bp[var6] = 2.0F; 1818 this.field_82179_bU = true; 1819 this.onItemPickup(var13, 1); 1820 var13.setDead(); 1821 } 1822 } 1823 } 1824 } 1825 } 1826 1827 this.worldObj.theProfiler.endSection(); 1828 } 1829 1830 protected void func_82167_n(Entity par1Entity) 1831 { 1832 par1Entity.applyEntityCollision(this); 1833 } 1834 1835 /** 1836 * Returns true if the newer Entity AI code should be run 1837 */ 1838 protected boolean isAIEnabled() 1839 { 1840 return false; 1841 } 1842 1843 /** 1844 * Returns whether the entity is in a local (client) world 1845 */ 1846 protected boolean isClientWorld() 1847 { 1848 return !this.worldObj.isRemote; 1849 } 1850 1851 /** 1852 * Dead and sleeping entities cannot move 1853 */ 1854 protected boolean isMovementBlocked() 1855 { 1856 return this.health <= 0; 1857 } 1858 1859 public boolean isBlocking() 1860 { 1861 return false; 1862 } 1863 1864 /** 1865 * Causes this entity to do an upwards motion (jumping). 1866 */ 1867 protected void jump() 1868 { 1869 this.motionY = 0.41999998688697815D; 1870 1871 if (this.isPotionActive(Potion.jump)) 1872 { 1873 this.motionY += (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F); 1874 } 1875 1876 if (this.isSprinting()) 1877 { 1878 float var1 = this.rotationYaw * 0.017453292F; 1879 this.motionX -= (double)(MathHelper.sin(var1) * 0.2F); 1880 this.motionZ += (double)(MathHelper.cos(var1) * 0.2F); 1881 } 1882 1883 this.isAirBorne = true; 1884 ForgeHooks.onLivingJump(this); 1885 } 1886 1887 /** 1888 * Determines if an entity can be despawned, used on idle far away entities 1889 */ 1890 protected boolean canDespawn() 1891 { 1892 return true; 1893 } 1894 1895 /** 1896 * Makes the entity despawn if requirements are reached 1897 */ 1898 protected void despawnEntity() 1899 { 1900 if (!this.field_82179_bU) 1901 { 1902 EntityPlayer var1 = this.worldObj.getClosestPlayerToEntity(this, -1.0D); 1903 1904 if (var1 != null) 1905 { 1906 double var2 = var1.posX - this.posX; 1907 double var4 = var1.posY - this.posY; 1908 double var6 = var1.posZ - this.posZ; 1909 double var8 = var2 * var2 + var4 * var4 + var6 * var6; 1910 1911 if (this.canDespawn() && var8 > 16384.0D) 1912 { 1913 this.setDead(); 1914 } 1915 1916 if (this.entityAge > 600 && this.rand.nextInt(800) == 0 && var8 > 1024.0D && this.canDespawn()) 1917 { 1918 this.setDead(); 1919 } 1920 else if (var8 < 1024.0D) 1921 { 1922 this.entityAge = 0; 1923 } 1924 } 1925 } 1926 } 1927 1928 protected void updateAITasks() 1929 { 1930 ++this.entityAge; 1931 this.worldObj.theProfiler.startSection("checkDespawn"); 1932 this.despawnEntity(); 1933 this.worldObj.theProfiler.endSection(); 1934 this.worldObj.theProfiler.startSection("sensing"); 1935 this.senses.clearSensingCache(); 1936 this.worldObj.theProfiler.endSection(); 1937 this.worldObj.theProfiler.startSection("targetSelector"); 1938 this.targetTasks.onUpdateTasks(); 1939 this.worldObj.theProfiler.endSection(); 1940 this.worldObj.theProfiler.startSection("goalSelector"); 1941 this.tasks.onUpdateTasks(); 1942 this.worldObj.theProfiler.endSection(); 1943 this.worldObj.theProfiler.startSection("navigation"); 1944 this.navigator.onUpdateNavigation(); 1945 this.worldObj.theProfiler.endSection(); 1946 this.worldObj.theProfiler.startSection("mob tick"); 1947 this.updateAITick(); 1948 this.worldObj.theProfiler.endSection(); 1949 this.worldObj.theProfiler.startSection("controls"); 1950 this.worldObj.theProfiler.startSection("move"); 1951 this.moveHelper.onUpdateMoveHelper(); 1952 this.worldObj.theProfiler.endStartSection("look"); 1953 this.lookHelper.onUpdateLook(); 1954 this.worldObj.theProfiler.endStartSection("jump"); 1955 this.jumpHelper.doJump(); 1956 this.worldObj.theProfiler.endSection(); 1957 this.worldObj.theProfiler.endSection(); 1958 } 1959 1960 /** 1961 * main AI tick function, replaces updateEntityActionState 1962 */ 1963 protected void updateAITick() {} 1964 1965 protected void updateEntityActionState() 1966 { 1967 ++this.entityAge; 1968 this.despawnEntity(); 1969 this.moveStrafing = 0.0F; 1970 this.moveForward = 0.0F; 1971 float var1 = 8.0F; 1972 1973 if (this.rand.nextFloat() < 0.02F) 1974 { 1975 EntityPlayer var2 = this.worldObj.getClosestPlayerToEntity(this, (double)var1); 1976 1977 if (var2 != null) 1978 { 1979 this.currentTarget = var2; 1980 this.numTicksToChaseTarget = 10 + this.rand.nextInt(20); 1981 } 1982 else 1983 { 1984 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F; 1985 } 1986 } 1987 1988 if (this.currentTarget != null) 1989 { 1990 this.faceEntity(this.currentTarget, 10.0F, (float)this.getVerticalFaceSpeed()); 1991 1992 if (this.numTicksToChaseTarget-- <= 0 || this.currentTarget.isDead || this.currentTarget.getDistanceSqToEntity(this) > (double)(var1 * var1)) 1993 { 1994 this.currentTarget = null; 1995 } 1996 } 1997 else 1998 { 1999 if (this.rand.nextFloat() < 0.05F) 2000 { 2001 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F; 2002 } 2003 2004 this.rotationYaw += this.randomYawVelocity; 2005 this.rotationPitch = this.defaultPitch; 2006 } 2007 2008 boolean var4 = this.isInWater(); 2009 boolean var3 = this.handleLavaMovement(); 2010 2011 if (var4 || var3) 2012 { 2013 this.isJumping = this.rand.nextFloat() < 0.8F; 2014 } 2015 } 2016 2017 protected void func_82168_bl() 2018 { 2019 int var1 = this.func_82166_i(); 2020 2021 if (this.field_82175_bq) 2022 { 2023 ++this.field_82173_br; 2024 2025 if (this.field_82173_br >= var1) 2026 { 2027 this.field_82173_br = 0; 2028 this.field_82175_bq = false; 2029 } 2030 } 2031 else 2032 { 2033 this.field_82173_br = 0; 2034 } 2035 2036 this.swingProgress = (float)this.field_82173_br / (float)var1; 2037 } 2038 2039 /** 2040 * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently 2041 * use in wolves. 2042 */ 2043 public int getVerticalFaceSpeed() 2044 { 2045 return 40; 2046 } 2047 2048 /** 2049 * Changes pitch and yaw so that the entity calling the function is facing the entity provided as an argument. 2050 */ 2051 public void faceEntity(Entity par1Entity, float par2, float par3) 2052 { 2053 double var4 = par1Entity.posX - this.posX; 2054 double var8 = par1Entity.posZ - this.posZ; 2055 double var6; 2056 2057 if (par1Entity instanceof EntityLiving) 2058 { 2059 EntityLiving var10 = (EntityLiving)par1Entity; 2060 var6 = this.posY + (double)this.getEyeHeight() - (var10.posY + (double)var10.getEyeHeight()); 2061 } 2062 else 2063 { 2064 var6 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight()); 2065 } 2066 2067 double var14 = (double)MathHelper.sqrt_double(var4 * var4 + var8 * var8); 2068 float var12 = (float)(Math.atan2(var8, var4) * 180.0D / Math.PI) - 90.0F; 2069 float var13 = (float)(-(Math.atan2(var6, var14) * 180.0D / Math.PI)); 2070 this.rotationPitch = -this.updateRotation(this.rotationPitch, var13, par3); 2071 this.rotationYaw = this.updateRotation(this.rotationYaw, var12, par2); 2072 } 2073 2074 /** 2075 * Arguments: current rotation, intended rotation, max increment. 2076 */ 2077 private float updateRotation(float par1, float par2, float par3) 2078 { 2079 float var4 = MathHelper.wrapAngleTo180_float(par2 - par1); 2080 2081 if (var4 > par3) 2082 { 2083 var4 = par3; 2084 } 2085 2086 if (var4 < -par3) 2087 { 2088 var4 = -par3; 2089 } 2090 2091 return par1 + var4; 2092 } 2093 2094 /** 2095 * Checks if the entity's current position is a valid location to spawn this entity. 2096 */ 2097 public boolean getCanSpawnHere() 2098 { 2099 return this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox); 2100 } 2101 2102 /** 2103 * sets the dead flag. Used when you fall off the bottom of the world. 2104 */ 2105 protected void kill() 2106 { 2107 this.attackEntityFrom(DamageSource.outOfWorld, 4); 2108 } 2109 2110 @SideOnly(Side.CLIENT) 2111 2112 /** 2113 * Returns where in the swing animation the living entity is (from 0 to 1). Args: partialTickTime 2114 */ 2115 public float getSwingProgress(float par1) 2116 { 2117 float var2 = this.swingProgress - this.prevSwingProgress; 2118 2119 if (var2 < 0.0F) 2120 { 2121 ++var2; 2122 } 2123 2124 return this.prevSwingProgress + var2 * par1; 2125 } 2126 2127 @SideOnly(Side.CLIENT) 2128 2129 /** 2130 * interpolated position vector 2131 */ 2132 public Vec3 getPosition(float par1) 2133 { 2134 if (par1 == 1.0F) 2135 { 2136 return this.worldObj.func_82732_R().getVecFromPool(this.posX, this.posY, this.posZ); 2137 } 2138 else 2139 { 2140 double var2 = this.prevPosX + (this.posX - this.prevPosX) * (double)par1; 2141 double var4 = this.prevPosY + (this.posY - this.prevPosY) * (double)par1; 2142 double var6 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double)par1; 2143 return this.worldObj.func_82732_R().getVecFromPool(var2, var4, var6); 2144 } 2145 } 2146 2147 /** 2148 * returns a (normalized) vector of where this entity is looking 2149 */ 2150 public Vec3 getLookVec() 2151 { 2152 return this.getLook(1.0F); 2153 } 2154 2155 /** 2156 * interpolated look vector 2157 */ 2158 public Vec3 getLook(float par1) 2159 { 2160 float var2; 2161 float var3; 2162 float var4; 2163 float var5; 2164 2165 if (par1 == 1.0F) 2166 { 2167 var2 = MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI); 2168 var3 = MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI); 2169 var4 = -MathHelper.cos(-this.rotationPitch * 0.017453292F); 2170 var5 = MathHelper.sin(-this.rotationPitch * 0.017453292F); 2171 return this.worldObj.func_82732_R().getVecFromPool((double)(var3 * var4), (double)var5, (double)(var2 * var4)); 2172 } 2173 else 2174 { 2175 var2 = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * par1; 2176 var3 = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * par1; 2177 var4 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI); 2178 var5 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI); 2179 float var6 = -MathHelper.cos(-var2 * 0.017453292F); 2180 float var7 = MathHelper.sin(-var2 * 0.017453292F); 2181 return this.worldObj.func_82732_R().getVecFromPool((double)(var5 * var6), (double)var7, (double)(var4 * var6)); 2182 } 2183 } 2184 2185 @SideOnly(Side.CLIENT) 2186 2187 /** 2188 * Returns render size modifier 2189 */ 2190 public float getRenderSizeModifier() 2191 { 2192 return 1.0F; 2193 } 2194 2195 @SideOnly(Side.CLIENT) 2196 2197 /** 2198 * Performs a ray trace for the distance specified and using the partial tick time. Args: distance, partialTickTime 2199 */ 2200 public MovingObjectPosition rayTrace(double par1, float par3) 2201 { 2202 Vec3 var4 = this.getPosition(par3); 2203 Vec3 var5 = this.getLook(par3); 2204 Vec3 var6 = var4.addVector(var5.xCoord * par1, var5.yCoord * par1, var5.zCoord * par1); 2205 return this.worldObj.rayTraceBlocks(var4, var6); 2206 } 2207 2208 /** 2209 * Will return how many at most can spawn in a chunk at once. 2210 */ 2211 public int getMaxSpawnedInChunk() 2212 { 2213 return 4; 2214 } 2215 2216 @SideOnly(Side.CLIENT) 2217 public void handleHealthUpdate(byte par1) 2218 { 2219 if (par1 == 2) 2220 { 2221 this.legYaw = 1.5F; 2222 this.hurtResistantTime = this.maxHurtResistantTime; 2223 this.hurtTime = this.maxHurtTime = 10; 2224 this.attackedAtYaw = 0.0F; 2225 this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); 2226 this.attackEntityFrom(DamageSource.generic, 0); 2227 } 2228 else if (par1 == 3) 2229 { 2230 this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); 2231 this.health = 0; 2232 this.onDeath(DamageSource.generic); 2233 } 2234 else 2235 { 2236 super.handleHealthUpdate(par1); 2237 } 2238 } 2239 2240 /** 2241 * Returns whether player is sleeping or not 2242 */ 2243 public boolean isPlayerSleeping() 2244 { 2245 return false; 2246 } 2247 2248 @SideOnly(Side.CLIENT) 2249 2250 /** 2251 * Gets the Icon Index of the item currently held 2252 */ 2253 public int getItemIcon(ItemStack par1ItemStack, int par2) 2254 { 2255 return par1ItemStack.getIconIndex(); 2256 } 2257 2258 protected void updatePotionEffects() 2259 { 2260 Iterator var1 = this.activePotionsMap.keySet().iterator(); 2261 2262 while (var1.hasNext()) 2263 { 2264 Integer var2 = (Integer)var1.next(); 2265 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2); 2266 2267 if (!var3.onUpdate(this) && !this.worldObj.isRemote) 2268 { 2269 var1.remove(); 2270 this.onFinishedPotionEffect(var3); 2271 } 2272 } 2273 2274 int var11; 2275 2276 if (this.potionsNeedUpdate) 2277 { 2278 if (!this.worldObj.isRemote) 2279 { 2280 if (this.activePotionsMap.isEmpty()) 2281 { 2282 this.dataWatcher.updateObject(9, Byte.valueOf((byte)0)); 2283 this.dataWatcher.updateObject(8, Integer.valueOf(0)); 2284 this.func_82142_c(false); 2285 } 2286 else 2287 { 2288 var11 = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values()); 2289 this.dataWatcher.updateObject(9, Byte.valueOf((byte)(PotionHelper.func_82817_b(this.activePotionsMap.values()) ? 1 : 0))); 2290 this.dataWatcher.updateObject(8, Integer.valueOf(var11)); 2291 this.func_82142_c(this.func_82165_m(Potion.invisibility.id)); 2292 } 2293 } 2294 2295 this.potionsNeedUpdate = false; 2296 } 2297 2298 var11 = this.dataWatcher.getWatchableObjectInt(8); 2299 boolean var12 = this.dataWatcher.getWatchableObjectByte(9) > 0; 2300 2301 if (var11 > 0) 2302 { 2303 boolean var4 = false; 2304 2305 if (!this.func_82150_aj()) 2306 { 2307 var4 = this.rand.nextBoolean(); 2308 } 2309 else 2310 { 2311 var4 = this.rand.nextInt(15) == 0; 2312 } 2313 2314 if (var12) 2315 { 2316 var4 &= this.rand.nextInt(5) == 0; 2317 } 2318 2319 if (var4 && var11 > 0) 2320 { 2321 double var5 = (double)(var11 >> 16 & 255) / 255.0D; 2322 double var7 = (double)(var11 >> 8 & 255) / 255.0D; 2323 double var9 = (double)(var11 >> 0 & 255) / 255.0D; 2324 this.worldObj.spawnParticle(var12 ? "mobSpellAmbient" : "mobSpell", this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height - (double)this.yOffset, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, var5, var7, var9); 2325 } 2326 } 2327 } 2328 2329 public void clearActivePotions() 2330 { 2331 Iterator var1 = this.activePotionsMap.keySet().iterator(); 2332 2333 while (var1.hasNext()) 2334 { 2335 Integer var2 = (Integer)var1.next(); 2336 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2); 2337 2338 if (!this.worldObj.isRemote) 2339 { 2340 var1.remove(); 2341 this.onFinishedPotionEffect(var3); 2342 } 2343 } 2344 } 2345 2346 public Collection getActivePotionEffects() 2347 { 2348 return this.activePotionsMap.values(); 2349 } 2350 2351 public boolean func_82165_m(int par1) 2352 { 2353 return this.activePotionsMap.containsKey(Integer.valueOf(par1)); 2354 } 2355 2356 public boolean isPotionActive(Potion par1Potion) 2357 { 2358 return this.activePotionsMap.containsKey(Integer.valueOf(par1Potion.id)); 2359 } 2360 2361 /** 2362 * returns the PotionEffect for the supplied Potion if it is active, null otherwise. 2363 */ 2364 public PotionEffect getActivePotionEffect(Potion par1Potion) 2365 { 2366 return (PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1Potion.id)); 2367 } 2368 2369 /** 2370 * adds a PotionEffect to the entity 2371 */ 2372 public void addPotionEffect(PotionEffect par1PotionEffect) 2373 { 2374 if (this.isPotionApplicable(par1PotionEffect)) 2375 { 2376 if (this.activePotionsMap.containsKey(Integer.valueOf(par1PotionEffect.getPotionID()))) 2377 { 2378 ((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))).combine(par1PotionEffect); 2379 this.onChangedPotionEffect((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))); 2380 } 2381 else 2382 { 2383 this.activePotionsMap.put(Integer.valueOf(par1PotionEffect.getPotionID()), par1PotionEffect); 2384 this.onNewPotionEffect(par1PotionEffect); 2385 } 2386 } 2387 } 2388 2389 public boolean isPotionApplicable(PotionEffect par1PotionEffect) 2390 { 2391 if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) 2392 { 2393 int var2 = par1PotionEffect.getPotionID(); 2394 2395 if (var2 == Potion.regeneration.id || var2 == Potion.poison.id) 2396 { 2397 return false; 2398 } 2399 } 2400 2401 return true; 2402 } 2403 2404 /** 2405 * Returns true if this entity is undead. 2406 */ 2407 public boolean isEntityUndead() 2408 { 2409 return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD; 2410 } 2411 2412 /** 2413 * input is the potion id to remove from the current active potion effects 2414 */ 2415 public void removePotionEffect(int par1) 2416 { 2417 this.activePotionsMap.remove(Integer.valueOf(par1)); 2418 } 2419 2420 public void func_82170_o(int par1) 2421 { 2422 PotionEffect var2 = (PotionEffect)this.activePotionsMap.remove(Integer.valueOf(par1)); 2423 2424 if (var2 != null) 2425 { 2426 this.onFinishedPotionEffect(var2); 2427 } 2428 } 2429 2430 protected void onNewPotionEffect(PotionEffect par1PotionEffect) 2431 { 2432 this.potionsNeedUpdate = true; 2433 } 2434 2435 protected void onChangedPotionEffect(PotionEffect par1PotionEffect) 2436 { 2437 this.potionsNeedUpdate = true; 2438 } 2439 2440 protected void onFinishedPotionEffect(PotionEffect par1PotionEffect) 2441 { 2442 this.potionsNeedUpdate = true; 2443 } 2444 2445 /** 2446 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown 2447 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities. 2448 */ 2449 public float getSpeedModifier() 2450 { 2451 float var1 = 1.0F; 2452 2453 if (this.isPotionActive(Potion.moveSpeed)) 2454 { 2455 var1 *= 1.0F + 0.2F * (float)(this.getActivePotionEffect(Potion.moveSpeed).getAmplifier() + 1); 2456 } 2457 2458 if (this.isPotionActive(Potion.moveSlowdown)) 2459 { 2460 var1 *= 1.0F - 0.15F * (float)(this.getActivePotionEffect(Potion.moveSlowdown).getAmplifier() + 1); 2461 } 2462 2463 return var1; 2464 } 2465 2466 /** 2467 * Move the entity to the coordinates informed, but keep yaw/pitch values. 2468 */ 2469 public void setPositionAndUpdate(double par1, double par3, double par5) 2470 { 2471 this.setLocationAndAngles(par1, par3, par5, this.rotationYaw, this.rotationPitch); 2472 } 2473 2474 /** 2475 * If Animal, checks if the age timer is negative 2476 */ 2477 public boolean isChild() 2478 { 2479 return false; 2480 } 2481 2482 /** 2483 * Get this Entity's EnumCreatureAttribute 2484 */ 2485 public EnumCreatureAttribute getCreatureAttribute() 2486 { 2487 return EnumCreatureAttribute.UNDEFINED; 2488 } 2489 2490 /** 2491 * Renders broken item particles using the given ItemStack 2492 */ 2493 public void renderBrokenItemStack(ItemStack par1ItemStack) 2494 { 2495 this.worldObj.playSoundAtEntity(this, "random.break", 0.8F, 0.8F + this.worldObj.rand.nextFloat() * 0.4F); 2496 2497 for (int var2 = 0; var2 < 5; ++var2) 2498 { 2499 Vec3 var3 = this.worldObj.func_82732_R().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); 2500 var3.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F); 2501 var3.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F); 2502 Vec3 var4 = this.worldObj.func_82732_R().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D); 2503 var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F); 2504 var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F); 2505 var4 = var4.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ); 2506 this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().shiftedIndex, var4.xCoord, var4.yCoord, var4.zCoord, var3.xCoord, var3.yCoord + 0.05D, var3.zCoord); 2507 } 2508 } 2509 2510 public int func_82143_as() 2511 { 2512 if (this.getAttackTarget() == null) 2513 { 2514 return 3; 2515 } 2516 else 2517 { 2518 int var1 = (int)((float)this.health - (float)this.getMaxHealth() * 0.33F); 2519 var1 -= (3 - this.worldObj.difficultySetting) * 4; 2520 2521 if (var1 < 0) 2522 { 2523 var1 = 0; 2524 } 2525 2526 return var1 + 3; 2527 } 2528 } 2529 2530 /** 2531 * Returns the item that this EntityLiving is holding, if any. 2532 */ 2533 public ItemStack getHeldItem() 2534 { 2535 return this.field_82182_bS[0]; 2536 } 2537 2538 /** 2539 * 0 = item, 1-n is armor 2540 */ 2541 public ItemStack getCurrentItemOrArmor(int par1) 2542 { 2543 return this.field_82182_bS[par1]; 2544 } 2545 2546 public ItemStack func_82169_q(int par1) 2547 { 2548 return this.field_82182_bS[par1 + 1]; 2549 } 2550 2551 public void func_70062_b(int par1, ItemStack par2ItemStack) 2552 { 2553 this.field_82182_bS[par1] = par2ItemStack; 2554 } 2555 2556 public ItemStack[] getLastActiveItems() 2557 { 2558 return this.field_82182_bS; 2559 } 2560 2561 protected void func_82160_b(boolean par1, int par2) 2562 { 2563 for (int var3 = 0; var3 < this.getLastActiveItems().length; ++var3) 2564 { 2565 ItemStack var4 = this.getCurrentItemOrArmor(var3); 2566 boolean var5 = this.field_82174_bp[var3] > 1.0F; 2567 2568 if (var4 != null && (par1 || var5) && this.rand.nextFloat() - (float)par2 * 0.01F < this.field_82174_bp[var3]) 2569 { 2570 if (!var5 && var4.isItemStackDamageable()) 2571 { 2572 int var6 = Math.max(var4.getMaxDamage() - 25, 1); 2573 int var7 = var4.getMaxDamage() - this.rand.nextInt(this.rand.nextInt(var6) + 1); 2574 2575 if (var7 > var6) 2576 { 2577 var7 = var6; 2578 } 2579 2580 if (var7 < 1) 2581 { 2582 var7 = 1; 2583 } 2584 2585 var4.setItemDamage(var7); 2586 } 2587 2588 this.entityDropItem(var4, 0.0F); 2589 } 2590 } 2591 } 2592 2593 protected void func_82164_bB() 2594 { 2595 if (this.rand.nextFloat() < field_82176_d[this.worldObj.difficultySetting]) 2596 { 2597 int var1 = this.rand.nextInt(2); 2598 float var2 = this.worldObj.difficultySetting == 3 ? 0.1F : 0.25F; 2599 2600 if (this.rand.nextFloat() < 0.07F) 2601 { 2602 ++var1; 2603 } 2604 2605 if (this.rand.nextFloat() < 0.07F) 2606 { 2607 ++var1; 2608 } 2609 2610 if (this.rand.nextFloat() < 0.07F) 2611 { 2612 ++var1; 2613 } 2614 2615 for (int var3 = 3; var3 >= 0; --var3) 2616 { 2617 ItemStack var4 = this.func_82169_q(var3); 2618 2619 if (var3 < 3 && this.rand.nextFloat() < var2) 2620 { 2621 break; 2622 } 2623 2624 if (var4 == null) 2625 { 2626 Item var5 = func_82161_a(var3 + 1, var1); 2627 2628 if (var5 != null) 2629 { 2630 this.func_70062_b(var3 + 1, new ItemStack(var5)); 2631 } 2632 } 2633 } 2634 } 2635 } 2636 2637 /** 2638 * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize 2639 */ 2640 public void onItemPickup(Entity par1Entity, int par2) 2641 { 2642 if (!par1Entity.isDead && !this.worldObj.isRemote) 2643 { 2644 EntityTracker var3 = ((WorldServer)this.worldObj).getEntityTracker(); 2645 2646 if (par1Entity instanceof EntityItem) 2647 { 2648 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2649 } 2650 2651 if (par1Entity instanceof EntityArrow) 2652 { 2653 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2654 } 2655 2656 if (par1Entity instanceof EntityXPOrb) 2657 { 2658 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2659 } 2660 } 2661 } 2662 2663 public static int func_82159_b(ItemStack par0ItemStack) 2664 { 2665 if (par0ItemStack.itemID != Block.pumpkin.blockID && par0ItemStack.itemID != Item.field_82799_bQ.shiftedIndex) 2666 { 2667 if (par0ItemStack.getItem() instanceof ItemArmor) 2668 { 2669 switch (((ItemArmor)par0ItemStack.getItem()).armorType) 2670 { 2671 case 0: 2672 return 4; 2673 case 1: 2674 return 3; 2675 case 2: 2676 return 2; 2677 case 3: 2678 return 1; 2679 } 2680 } 2681 2682 return 0; 2683 } 2684 else 2685 { 2686 return 4; 2687 } 2688 } 2689 2690 public static Item func_82161_a(int par0, int par1) 2691 { 2692 switch (par0) 2693 { 2694 case 4: 2695 if (par1 == 0) 2696 { 2697 return Item.helmetLeather; 2698 } 2699 else if (par1 == 1) 2700 { 2701 return Item.helmetGold; 2702 } 2703 else if (par1 == 2) 2704 { 2705 return Item.helmetChain; 2706 } 2707 else if (par1 == 3) 2708 { 2709 return Item.helmetSteel; 2710 } 2711 else if (par1 == 4) 2712 { 2713 return Item.helmetDiamond; 2714 } 2715 case 3: 2716 if (par1 == 0) 2717 { 2718 return Item.plateLeather; 2719 } 2720 else if (par1 == 1) 2721 { 2722 return Item.plateGold; 2723 } 2724 else if (par1 == 2) 2725 { 2726 return Item.plateChain; 2727 } 2728 else if (par1 == 3) 2729 { 2730 return Item.plateSteel; 2731 } 2732 else if (par1 == 4) 2733 { 2734 return Item.plateDiamond; 2735 } 2736 case 2: 2737 if (par1 == 0) 2738 { 2739 return Item.legsLeather; 2740 } 2741 else if (par1 == 1) 2742 { 2743 return Item.legsGold; 2744 } 2745 else if (par1 == 2) 2746 { 2747 return Item.legsChain; 2748 } 2749 else if (par1 == 3) 2750 { 2751 return Item.legsSteel; 2752 } 2753 else if (par1 == 4) 2754 { 2755 return Item.legsDiamond; 2756 } 2757 case 1: 2758 if (par1 == 0) 2759 { 2760 return Item.bootsLeather; 2761 } 2762 else if (par1 == 1) 2763 { 2764 return Item.bootsGold; 2765 } 2766 else if (par1 == 2) 2767 { 2768 return Item.bootsChain; 2769 } 2770 else if (par1 == 3) 2771 { 2772 return Item.bootsSteel; 2773 } 2774 else if (par1 == 4) 2775 { 2776 return Item.bootsDiamond; 2777 } 2778 default: 2779 return null; 2780 } 2781 } 2782 2783 protected void func_82162_bC() 2784 { 2785 if (this.getHeldItem() != null && this.rand.nextFloat() < field_82177_b[this.worldObj.difficultySetting]) 2786 { 2787 EnchantmentHelper.addRandomEnchantment(this.rand, this.getHeldItem(), 5); 2788 } 2789 2790 for (int var1 = 0; var1 < 4; ++var1) 2791 { 2792 ItemStack var2 = this.func_82169_q(var1); 2793 2794 if (var2 != null && this.rand.nextFloat() < field_82178_c[this.worldObj.difficultySetting]) 2795 { 2796 EnchantmentHelper.addRandomEnchantment(this.rand, var2, 5); 2797 } 2798 } 2799 } 2800 2801 public void func_82163_bD() {} 2802 2803 private int func_82166_i() 2804 { 2805 return this.isPotionActive(Potion.digSpeed) ? 6 - (1 + this.getActivePotionEffect(Potion.digSpeed).getAmplifier()) * 1 : (this.isPotionActive(Potion.digSlowdown) ? 6 + (1 + this.getActivePotionEffect(Potion.digSlowdown).getAmplifier()) * 2 : 6); 2806 } 2807 2808 /** 2809 * Swings the item the player is holding. 2810 */ 2811 public void swingItem() 2812 { 2813 if (!this.field_82175_bq || this.field_82173_br >= this.func_82166_i() / 2 || this.field_82173_br < 0) 2814 { 2815 this.field_82173_br = -1; 2816 this.field_82175_bq = true; 2817 2818 if (this.worldObj instanceof WorldServer) 2819 { 2820 ((WorldServer)this.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, new Packet18Animation(this, 1)); 2821 } 2822 } 2823 } 2824 2825 public boolean func_82171_bF() 2826 { 2827 return false; 2828 } 2829 2830 /*** 2831 * Removes all potion effects that have curativeItem as a curative item for its effect 2832 * @param curativeItem The itemstack we are using to cure potion effects 2833 */ 2834 public void curePotionEffects(ItemStack curativeItem) 2835 { 2836 Iterator<Integer> potionKey = activePotionsMap.keySet().iterator(); 2837 2838 if (worldObj.isRemote) 2839 { 2840 return; 2841 } 2842 2843 while (potionKey.hasNext()) 2844 { 2845 Integer key = potionKey.next(); 2846 PotionEffect effect = (PotionEffect)activePotionsMap.get(key); 2847 2848 if (effect.isCurativeItem(curativeItem)) 2849 { 2850 potionKey.remove(); 2851 onFinishedPotionEffect(effect); 2852 } 2853 } 2854 } 2855 }