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