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