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