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