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