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