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