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