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.playSound(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.isEntityInvulnerable()) 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.explosion2) 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.playSound(this.getDeathSound(), this.getSoundVolume(), this.getSoundPitch()); 1109 } 1110 1111 this.onDeath(par1DamageSource); 1112 } 1113 else if (var3) 1114 { 1115 this.playSound(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.isEntityInvulnerable()) 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. @param par1 - Whether this entity has recently been hit by a player. @param 1344 * par2 - Level of Looting used to kill this mob. 1345 */ 1346 protected void dropFewItems(boolean par1, int par2) 1347 { 1348 int var3 = this.getDropItemId(); 1349 1350 if (var3 > 0) 1351 { 1352 int var4 = this.rand.nextInt(3); 1353 1354 if (par2 > 0) 1355 { 1356 var4 += this.rand.nextInt(par2 + 1); 1357 } 1358 1359 for (int var5 = 0; var5 < var4; ++var5) 1360 { 1361 this.dropItem(var3, 1); 1362 } 1363 } 1364 } 1365 1366 /** 1367 * Returns the item ID for the item the mob drops on death. 1368 */ 1369 protected int getDropItemId() 1370 { 1371 return 0; 1372 } 1373 1374 /** 1375 * Called when the mob is falling. Calculates and applies fall damage. 1376 */ 1377 protected void fall(float par1) 1378 { 1379 par1 = ForgeHooks.onLivingFall(this, par1); 1380 if (par1 <= 0) 1381 { 1382 return; 1383 } 1384 1385 super.fall(par1); 1386 int var2 = MathHelper.ceiling_float_int(par1 - 3.0F); 1387 1388 if (var2 > 0) 1389 { 1390 if (var2 > 4) 1391 { 1392 this.playSound("damage.fallbig", 1.0F, 1.0F); 1393 } 1394 else 1395 { 1396 this.playSound("damage.fallsmall", 1.0F, 1.0F); 1397 } 1398 1399 this.attackEntityFrom(DamageSource.fall, var2); 1400 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)); 1401 1402 if (var3 > 0) 1403 { 1404 StepSound var4 = Block.blocksList[var3].stepSound; 1405 this.playSound(var4.getStepSound(), var4.getVolume() * 0.5F, var4.getPitch() * 0.75F); 1406 } 1407 } 1408 } 1409 1410 /** 1411 * Moves the entity based on the specified heading. Args: strafe, forward 1412 */ 1413 public void moveEntityWithHeading(float par1, float par2) 1414 { 1415 double var9; 1416 1417 if (this.isInWater() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying)) 1418 { 1419 var9 = this.posY; 1420 this.moveFlying(par1, par2, this.isAIEnabled() ? 0.04F : 0.02F); 1421 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1422 this.motionX *= 0.800000011920929D; 1423 this.motionY *= 0.800000011920929D; 1424 this.motionZ *= 0.800000011920929D; 1425 this.motionY -= 0.02D; 1426 1427 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ)) 1428 { 1429 this.motionY = 0.30000001192092896D; 1430 } 1431 } 1432 else if (this.handleLavaMovement() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying)) 1433 { 1434 var9 = this.posY; 1435 this.moveFlying(par1, par2, 0.02F); 1436 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1437 this.motionX *= 0.5D; 1438 this.motionY *= 0.5D; 1439 this.motionZ *= 0.5D; 1440 this.motionY -= 0.02D; 1441 1442 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ)) 1443 { 1444 this.motionY = 0.30000001192092896D; 1445 } 1446 } 1447 else 1448 { 1449 float var3 = 0.91F; 1450 1451 if (this.onGround) 1452 { 1453 var3 = 0.54600006F; 1454 int var4 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ)); 1455 1456 if (var4 > 0) 1457 { 1458 var3 = Block.blocksList[var4].slipperiness * 0.91F; 1459 } 1460 } 1461 1462 float var8 = 0.16277136F / (var3 * var3 * var3); 1463 float var5; 1464 1465 if (this.onGround) 1466 { 1467 if (this.isAIEnabled()) 1468 { 1469 var5 = this.getAIMoveSpeed(); 1470 } 1471 else 1472 { 1473 var5 = this.landMovementFactor; 1474 } 1475 1476 var5 *= var8; 1477 } 1478 else 1479 { 1480 var5 = this.jumpMovementFactor; 1481 } 1482 1483 this.moveFlying(par1, par2, var5); 1484 var3 = 0.91F; 1485 1486 if (this.onGround) 1487 { 1488 var3 = 0.54600006F; 1489 int var6 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ)); 1490 1491 if (var6 > 0) 1492 { 1493 var3 = Block.blocksList[var6].slipperiness * 0.91F; 1494 } 1495 } 1496 1497 if (this.isOnLadder()) 1498 { 1499 float var10 = 0.15F; 1500 1501 if (this.motionX < (double)(-var10)) 1502 { 1503 this.motionX = (double)(-var10); 1504 } 1505 1506 if (this.motionX > (double)var10) 1507 { 1508 this.motionX = (double)var10; 1509 } 1510 1511 if (this.motionZ < (double)(-var10)) 1512 { 1513 this.motionZ = (double)(-var10); 1514 } 1515 1516 if (this.motionZ > (double)var10) 1517 { 1518 this.motionZ = (double)var10; 1519 } 1520 1521 this.fallDistance = 0.0F; 1522 1523 if (this.motionY < -0.15D) 1524 { 1525 this.motionY = -0.15D; 1526 } 1527 1528 boolean var7 = this.isSneaking() && this instanceof EntityPlayer; 1529 1530 if (var7 && this.motionY < 0.0D) 1531 { 1532 this.motionY = 0.0D; 1533 } 1534 } 1535 1536 this.moveEntity(this.motionX, this.motionY, this.motionZ); 1537 1538 if (this.isCollidedHorizontally && this.isOnLadder()) 1539 { 1540 this.motionY = 0.2D; 1541 } 1542 1543 if (this.worldObj.isRemote && (!this.worldObj.blockExists((int)this.posX, 0, (int)this.posZ) || !this.worldObj.getChunkFromBlockCoords((int)this.posX, (int)this.posZ).isChunkLoaded)) 1544 { 1545 if (this.posY > 0.0D) 1546 { 1547 this.motionY = -0.1D; 1548 } 1549 else 1550 { 1551 this.motionY = 0.0D; 1552 } 1553 } 1554 else 1555 { 1556 this.motionY -= 0.08D; 1557 } 1558 1559 this.motionY *= 0.9800000190734863D; 1560 this.motionX *= (double)var3; 1561 this.motionZ *= (double)var3; 1562 } 1563 1564 this.prevLegYaw = this.legYaw; 1565 var9 = this.posX - this.prevPosX; 1566 double var12 = this.posZ - this.prevPosZ; 1567 float var11 = MathHelper.sqrt_double(var9 * var9 + var12 * var12) * 4.0F; 1568 1569 if (var11 > 1.0F) 1570 { 1571 var11 = 1.0F; 1572 } 1573 1574 this.legYaw += (var11 - this.legYaw) * 0.4F; 1575 this.legSwing += this.legYaw; 1576 } 1577 1578 /** 1579 * returns true if this entity is by a ladder, false otherwise 1580 */ 1581 public boolean isOnLadder() 1582 { 1583 int var1 = MathHelper.floor_double(this.posX); 1584 int var2 = MathHelper.floor_double(this.boundingBox.minY); 1585 int var3 = MathHelper.floor_double(this.posZ); 1586 int var4 = this.worldObj.getBlockId(var1, var2, var3); 1587 return ForgeHooks.isLivingOnLadder(Block.blocksList[var4], worldObj, var1, var2, var3); 1588 } 1589 1590 /** 1591 * (abstract) Protected helper method to write subclass entity data to NBT. 1592 */ 1593 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 1594 { 1595 if (this.health < -32768) 1596 { 1597 this.health = -32768; 1598 } 1599 1600 par1NBTTagCompound.setShort("Health", (short)this.health); 1601 par1NBTTagCompound.setShort("HurtTime", (short)this.hurtTime); 1602 par1NBTTagCompound.setShort("DeathTime", (short)this.deathTime); 1603 par1NBTTagCompound.setShort("AttackTime", (short)this.attackTime); 1604 par1NBTTagCompound.setBoolean("CanPickUpLoot", this.canPickUpLoot); 1605 par1NBTTagCompound.setBoolean("PersistenceRequired", this.persistenceRequired); 1606 NBTTagList var2 = new NBTTagList(); 1607 1608 for (int var3 = 0; var3 < this.equipment.length; ++var3) 1609 { 1610 NBTTagCompound var4 = new NBTTagCompound(); 1611 1612 if (this.equipment[var3] != null) 1613 { 1614 this.equipment[var3].writeToNBT(var4); 1615 } 1616 1617 var2.appendTag(var4); 1618 } 1619 1620 par1NBTTagCompound.setTag("Equipment", var2); 1621 NBTTagList var6; 1622 1623 if (!this.activePotionsMap.isEmpty()) 1624 { 1625 var6 = new NBTTagList(); 1626 Iterator var7 = this.activePotionsMap.values().iterator(); 1627 1628 while (var7.hasNext()) 1629 { 1630 PotionEffect var5 = (PotionEffect)var7.next(); 1631 var6.appendTag(var5.writeCustomPotionEffectToNBT(new NBTTagCompound())); 1632 } 1633 1634 par1NBTTagCompound.setTag("ActiveEffects", var6); 1635 } 1636 1637 var6 = new NBTTagList(); 1638 1639 for (int var8 = 0; var8 < this.equipmentDropChances.length; ++var8) 1640 { 1641 var6.appendTag(new NBTTagFloat(var8 + "", this.equipmentDropChances[var8])); 1642 } 1643 1644 par1NBTTagCompound.setTag("DropChances", var6); 1645 } 1646 1647 /** 1648 * (abstract) Protected helper method to read subclass entity data from NBT. 1649 */ 1650 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 1651 { 1652 this.health = par1NBTTagCompound.getShort("Health"); 1653 1654 if (!par1NBTTagCompound.hasKey("Health")) 1655 { 1656 this.health = this.getMaxHealth(); 1657 } 1658 1659 this.hurtTime = par1NBTTagCompound.getShort("HurtTime"); 1660 this.deathTime = par1NBTTagCompound.getShort("DeathTime"); 1661 this.attackTime = par1NBTTagCompound.getShort("AttackTime"); 1662 this.canPickUpLoot = par1NBTTagCompound.getBoolean("CanPickUpLoot"); 1663 this.persistenceRequired = par1NBTTagCompound.getBoolean("PersistenceRequired"); 1664 NBTTagList var2; 1665 int var3; 1666 1667 if (par1NBTTagCompound.hasKey("Equipment")) 1668 { 1669 var2 = par1NBTTagCompound.getTagList("Equipment"); 1670 1671 for (var3 = 0; var3 < this.equipment.length; ++var3) 1672 { 1673 this.equipment[var3] = ItemStack.loadItemStackFromNBT((NBTTagCompound)var2.tagAt(var3)); 1674 } 1675 } 1676 1677 if (par1NBTTagCompound.hasKey("ActiveEffects")) 1678 { 1679 var2 = par1NBTTagCompound.getTagList("ActiveEffects"); 1680 1681 for (var3 = 0; var3 < var2.tagCount(); ++var3) 1682 { 1683 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3); 1684 PotionEffect var5 = PotionEffect.readCustomPotionEffectFromNBT(var4); 1685 this.activePotionsMap.put(Integer.valueOf(var5.getPotionID()), var5); 1686 } 1687 } 1688 1689 if (par1NBTTagCompound.hasKey("DropChances")) 1690 { 1691 var2 = par1NBTTagCompound.getTagList("DropChances"); 1692 1693 for (var3 = 0; var3 < var2.tagCount(); ++var3) 1694 { 1695 this.equipmentDropChances[var3] = ((NBTTagFloat)var2.tagAt(var3)).data; 1696 } 1697 } 1698 } 1699 1700 /** 1701 * Checks whether target entity is alive. 1702 */ 1703 public boolean isEntityAlive() 1704 { 1705 return !this.isDead && this.health > 0; 1706 } 1707 1708 public boolean canBreatheUnderwater() 1709 { 1710 return false; 1711 } 1712 1713 public void setMoveForward(float par1) 1714 { 1715 this.moveForward = par1; 1716 } 1717 1718 public void setJumping(boolean par1) 1719 { 1720 this.isJumping = par1; 1721 } 1722 1723 /** 1724 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons 1725 * use this to react to sunlight and start to burn. 1726 */ 1727 public void onLivingUpdate() 1728 { 1729 if (this.jumpTicks > 0) 1730 { 1731 --this.jumpTicks; 1732 } 1733 1734 if (this.newPosRotationIncrements > 0) 1735 { 1736 double var1 = this.posX + (this.newPosX - this.posX) / (double)this.newPosRotationIncrements; 1737 double var3 = this.posY + (this.newPosY - this.posY) / (double)this.newPosRotationIncrements; 1738 double var5 = this.posZ + (this.newPosZ - this.posZ) / (double)this.newPosRotationIncrements; 1739 double var7 = MathHelper.wrapAngleTo180_double(this.newRotationYaw - (double)this.rotationYaw); 1740 this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.newPosRotationIncrements); 1741 this.rotationPitch = (float)((double)this.rotationPitch + (this.newRotationPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements); 1742 --this.newPosRotationIncrements; 1743 this.setPosition(var1, var3, var5); 1744 this.setRotation(this.rotationYaw, this.rotationPitch); 1745 } 1746 else if (!this.isClientWorld()) 1747 { 1748 this.motionX *= 0.98D; 1749 this.motionY *= 0.98D; 1750 this.motionZ *= 0.98D; 1751 } 1752 1753 if (Math.abs(this.motionX) < 0.005D) 1754 { 1755 this.motionX = 0.0D; 1756 } 1757 1758 if (Math.abs(this.motionY) < 0.005D) 1759 { 1760 this.motionY = 0.0D; 1761 } 1762 1763 if (Math.abs(this.motionZ) < 0.005D) 1764 { 1765 this.motionZ = 0.0D; 1766 } 1767 1768 this.worldObj.theProfiler.startSection("ai"); 1769 1770 if (this.isMovementBlocked()) 1771 { 1772 this.isJumping = false; 1773 this.moveStrafing = 0.0F; 1774 this.moveForward = 0.0F; 1775 this.randomYawVelocity = 0.0F; 1776 } 1777 else if (this.isClientWorld()) 1778 { 1779 if (this.isAIEnabled()) 1780 { 1781 this.worldObj.theProfiler.startSection("newAi"); 1782 this.updateAITasks(); 1783 this.worldObj.theProfiler.endSection(); 1784 } 1785 else 1786 { 1787 this.worldObj.theProfiler.startSection("oldAi"); 1788 this.updateEntityActionState(); 1789 this.worldObj.theProfiler.endSection(); 1790 this.rotationYawHead = this.rotationYaw; 1791 } 1792 } 1793 1794 this.worldObj.theProfiler.endSection(); 1795 this.worldObj.theProfiler.startSection("jump"); 1796 1797 if (this.isJumping) 1798 { 1799 if (!this.isInWater() && !this.handleLavaMovement()) 1800 { 1801 if (this.onGround && this.jumpTicks == 0) 1802 { 1803 this.jump(); 1804 this.jumpTicks = 10; 1805 } 1806 } 1807 else 1808 { 1809 this.motionY += 0.03999999910593033D; 1810 } 1811 } 1812 else 1813 { 1814 this.jumpTicks = 0; 1815 } 1816 1817 this.worldObj.theProfiler.endSection(); 1818 this.worldObj.theProfiler.startSection("travel"); 1819 this.moveStrafing *= 0.98F; 1820 this.moveForward *= 0.98F; 1821 this.randomYawVelocity *= 0.9F; 1822 float var11 = this.landMovementFactor; 1823 this.landMovementFactor *= this.getSpeedModifier(); 1824 this.moveEntityWithHeading(this.moveStrafing, this.moveForward); 1825 this.landMovementFactor = var11; 1826 this.worldObj.theProfiler.endSection(); 1827 this.worldObj.theProfiler.startSection("push"); 1828 1829 if (!this.worldObj.isRemote) 1830 { 1831 this.func_85033_bc(); 1832 } 1833 1834 this.worldObj.theProfiler.endSection(); 1835 this.worldObj.theProfiler.startSection("looting"); 1836 1837 if (!this.worldObj.isRemote && this.canPickUpLoot && !this.dead && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing")) 1838 { 1839 List var2 = this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.boundingBox.expand(1.0D, 0.0D, 1.0D)); 1840 Iterator var12 = var2.iterator(); 1841 1842 while (var12.hasNext()) 1843 { 1844 EntityItem var4 = (EntityItem)var12.next(); 1845 1846 if (!var4.isDead && var4.func_92014_d() != null) 1847 { 1848 ItemStack var13 = var4.func_92014_d(); 1849 int var6 = func_82159_b(var13); 1850 1851 if (var6 > -1) 1852 { 1853 boolean var14 = true; 1854 ItemStack var8 = this.getCurrentItemOrArmor(var6); 1855 1856 if (var8 != null) 1857 { 1858 if (var6 == 0) 1859 { 1860 if (var13.getItem() instanceof ItemSword && !(var8.getItem() instanceof ItemSword)) 1861 { 1862 var14 = true; 1863 } 1864 else if (var13.getItem() instanceof ItemSword && var8.getItem() instanceof ItemSword) 1865 { 1866 ItemSword var9 = (ItemSword)var13.getItem(); 1867 ItemSword var10 = (ItemSword)var8.getItem(); 1868 1869 if (var9.func_82803_g() == var10.func_82803_g()) 1870 { 1871 var14 = var13.getItemDamage() > var8.getItemDamage() || var13.hasTagCompound() && !var8.hasTagCompound(); 1872 } 1873 else 1874 { 1875 var14 = var9.func_82803_g() > var10.func_82803_g(); 1876 } 1877 } 1878 else 1879 { 1880 var14 = false; 1881 } 1882 } 1883 else if (var13.getItem() instanceof ItemArmor && !(var8.getItem() instanceof ItemArmor)) 1884 { 1885 var14 = true; 1886 } 1887 else if (var13.getItem() instanceof ItemArmor && var8.getItem() instanceof ItemArmor) 1888 { 1889 ItemArmor var15 = (ItemArmor)var13.getItem(); 1890 ItemArmor var16 = (ItemArmor)var8.getItem(); 1891 1892 if (var15.damageReduceAmount == var16.damageReduceAmount) 1893 { 1894 var14 = var13.getItemDamage() > var8.getItemDamage() || var13.hasTagCompound() && !var8.hasTagCompound(); 1895 } 1896 else 1897 { 1898 var14 = var15.damageReduceAmount > var16.damageReduceAmount; 1899 } 1900 } 1901 else 1902 { 1903 var14 = false; 1904 } 1905 } 1906 1907 if (var14) 1908 { 1909 if (var8 != null && this.rand.nextFloat() - 0.1F < this.equipmentDropChances[var6]) 1910 { 1911 this.entityDropItem(var8, 0.0F); 1912 } 1913 1914 this.setCurrentItemOrArmor(var6, var13); 1915 this.equipmentDropChances[var6] = 2.0F; 1916 this.persistenceRequired = true; 1917 this.onItemPickup(var4, 1); 1918 var4.setDead(); 1919 } 1920 } 1921 } 1922 } 1923 } 1924 1925 this.worldObj.theProfiler.endSection(); 1926 } 1927 1928 protected void func_85033_bc() 1929 { 1930 List var1 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D)); 1931 1932 if (var1 != null && !var1.isEmpty()) 1933 { 1934 for (int var2 = 0; var2 < var1.size(); ++var2) 1935 { 1936 Entity var3 = (Entity)var1.get(var2); 1937 1938 if (var3.canBePushed()) 1939 { 1940 this.collideWithEntity(var3); 1941 } 1942 } 1943 } 1944 } 1945 1946 protected void collideWithEntity(Entity par1Entity) 1947 { 1948 par1Entity.applyEntityCollision(this); 1949 } 1950 1951 /** 1952 * Returns true if the newer Entity AI code should be run 1953 */ 1954 protected boolean isAIEnabled() 1955 { 1956 return false; 1957 } 1958 1959 /** 1960 * Returns whether the entity is in a local (client) world 1961 */ 1962 protected boolean isClientWorld() 1963 { 1964 return !this.worldObj.isRemote; 1965 } 1966 1967 /** 1968 * Dead and sleeping entities cannot move 1969 */ 1970 protected boolean isMovementBlocked() 1971 { 1972 return this.health <= 0; 1973 } 1974 1975 public boolean isBlocking() 1976 { 1977 return false; 1978 } 1979 1980 /** 1981 * Causes this entity to do an upwards motion (jumping). 1982 */ 1983 protected void jump() 1984 { 1985 this.motionY = 0.41999998688697815D; 1986 1987 if (this.isPotionActive(Potion.jump)) 1988 { 1989 this.motionY += (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F); 1990 } 1991 1992 if (this.isSprinting()) 1993 { 1994 float var1 = this.rotationYaw * 0.017453292F; 1995 this.motionX -= (double)(MathHelper.sin(var1) * 0.2F); 1996 this.motionZ += (double)(MathHelper.cos(var1) * 0.2F); 1997 } 1998 1999 this.isAirBorne = true; 2000 ForgeHooks.onLivingJump(this); 2001 } 2002 2003 /** 2004 * Determines if an entity can be despawned, used on idle far away entities 2005 */ 2006 protected boolean canDespawn() 2007 { 2008 return true; 2009 } 2010 2011 /** 2012 * Makes the entity despawn if requirements are reached 2013 */ 2014 protected void despawnEntity() 2015 { 2016 if (!this.persistenceRequired) 2017 { 2018 EntityPlayer var1 = this.worldObj.getClosestPlayerToEntity(this, -1.0D); 2019 2020 if (var1 != null) 2021 { 2022 double var2 = var1.posX - this.posX; 2023 double var4 = var1.posY - this.posY; 2024 double var6 = var1.posZ - this.posZ; 2025 double var8 = var2 * var2 + var4 * var4 + var6 * var6; 2026 2027 if (this.canDespawn() && var8 > 16384.0D) 2028 { 2029 this.setDead(); 2030 } 2031 2032 if (this.entityAge > 600 && this.rand.nextInt(800) == 0 && var8 > 1024.0D && this.canDespawn()) 2033 { 2034 this.setDead(); 2035 } 2036 else if (var8 < 1024.0D) 2037 { 2038 this.entityAge = 0; 2039 } 2040 } 2041 } 2042 } 2043 2044 protected void updateAITasks() 2045 { 2046 ++this.entityAge; 2047 this.worldObj.theProfiler.startSection("checkDespawn"); 2048 this.despawnEntity(); 2049 this.worldObj.theProfiler.endSection(); 2050 this.worldObj.theProfiler.startSection("sensing"); 2051 this.senses.clearSensingCache(); 2052 this.worldObj.theProfiler.endSection(); 2053 this.worldObj.theProfiler.startSection("targetSelector"); 2054 this.targetTasks.onUpdateTasks(); 2055 this.worldObj.theProfiler.endSection(); 2056 this.worldObj.theProfiler.startSection("goalSelector"); 2057 this.tasks.onUpdateTasks(); 2058 this.worldObj.theProfiler.endSection(); 2059 this.worldObj.theProfiler.startSection("navigation"); 2060 this.navigator.onUpdateNavigation(); 2061 this.worldObj.theProfiler.endSection(); 2062 this.worldObj.theProfiler.startSection("mob tick"); 2063 this.updateAITick(); 2064 this.worldObj.theProfiler.endSection(); 2065 this.worldObj.theProfiler.startSection("controls"); 2066 this.worldObj.theProfiler.startSection("move"); 2067 this.moveHelper.onUpdateMoveHelper(); 2068 this.worldObj.theProfiler.endStartSection("look"); 2069 this.lookHelper.onUpdateLook(); 2070 this.worldObj.theProfiler.endStartSection("jump"); 2071 this.jumpHelper.doJump(); 2072 this.worldObj.theProfiler.endSection(); 2073 this.worldObj.theProfiler.endSection(); 2074 } 2075 2076 /** 2077 * main AI tick function, replaces updateEntityActionState 2078 */ 2079 protected void updateAITick() {} 2080 2081 protected void updateEntityActionState() 2082 { 2083 ++this.entityAge; 2084 this.despawnEntity(); 2085 this.moveStrafing = 0.0F; 2086 this.moveForward = 0.0F; 2087 float var1 = 8.0F; 2088 2089 if (this.rand.nextFloat() < 0.02F) 2090 { 2091 EntityPlayer var2 = this.worldObj.getClosestPlayerToEntity(this, (double)var1); 2092 2093 if (var2 != null) 2094 { 2095 this.currentTarget = var2; 2096 this.numTicksToChaseTarget = 10 + this.rand.nextInt(20); 2097 } 2098 else 2099 { 2100 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F; 2101 } 2102 } 2103 2104 if (this.currentTarget != null) 2105 { 2106 this.faceEntity(this.currentTarget, 10.0F, (float)this.getVerticalFaceSpeed()); 2107 2108 if (this.numTicksToChaseTarget-- <= 0 || this.currentTarget.isDead || this.currentTarget.getDistanceSqToEntity(this) > (double)(var1 * var1)) 2109 { 2110 this.currentTarget = null; 2111 } 2112 } 2113 else 2114 { 2115 if (this.rand.nextFloat() < 0.05F) 2116 { 2117 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F; 2118 } 2119 2120 this.rotationYaw += this.randomYawVelocity; 2121 this.rotationPitch = this.defaultPitch; 2122 } 2123 2124 boolean var4 = this.isInWater(); 2125 boolean var3 = this.handleLavaMovement(); 2126 2127 if (var4 || var3) 2128 { 2129 this.isJumping = this.rand.nextFloat() < 0.8F; 2130 } 2131 } 2132 2133 /** 2134 * Updates the arm swing progress counters and animation progress 2135 */ 2136 protected void updateArmSwingProgress() 2137 { 2138 int var1 = this.getArmSwingAnimationEnd(); 2139 2140 if (this.isSwingInProgress) 2141 { 2142 ++this.swingProgressInt; 2143 2144 if (this.swingProgressInt >= var1) 2145 { 2146 this.swingProgressInt = 0; 2147 this.isSwingInProgress = false; 2148 } 2149 } 2150 else 2151 { 2152 this.swingProgressInt = 0; 2153 } 2154 2155 this.swingProgress = (float)this.swingProgressInt / (float)var1; 2156 } 2157 2158 /** 2159 * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently 2160 * use in wolves. 2161 */ 2162 public int getVerticalFaceSpeed() 2163 { 2164 return 40; 2165 } 2166 2167 /** 2168 * Changes pitch and yaw so that the entity calling the function is facing the entity provided as an argument. 2169 */ 2170 public void faceEntity(Entity par1Entity, float par2, float par3) 2171 { 2172 double var4 = par1Entity.posX - this.posX; 2173 double var8 = par1Entity.posZ - this.posZ; 2174 double var6; 2175 2176 if (par1Entity instanceof EntityLiving) 2177 { 2178 EntityLiving var10 = (EntityLiving)par1Entity; 2179 var6 = this.posY + (double)this.getEyeHeight() - (var10.posY + (double)var10.getEyeHeight()); 2180 } 2181 else 2182 { 2183 var6 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight()); 2184 } 2185 2186 double var14 = (double)MathHelper.sqrt_double(var4 * var4 + var8 * var8); 2187 float var12 = (float)(Math.atan2(var8, var4) * 180.0D / Math.PI) - 90.0F; 2188 float var13 = (float)(-(Math.atan2(var6, var14) * 180.0D / Math.PI)); 2189 this.rotationPitch = -this.updateRotation(this.rotationPitch, var13, par3); 2190 this.rotationYaw = this.updateRotation(this.rotationYaw, var12, par2); 2191 } 2192 2193 /** 2194 * Arguments: current rotation, intended rotation, max increment. 2195 */ 2196 private float updateRotation(float par1, float par2, float par3) 2197 { 2198 float var4 = MathHelper.wrapAngleTo180_float(par2 - par1); 2199 2200 if (var4 > par3) 2201 { 2202 var4 = par3; 2203 } 2204 2205 if (var4 < -par3) 2206 { 2207 var4 = -par3; 2208 } 2209 2210 return par1 + var4; 2211 } 2212 2213 /** 2214 * Checks if the entity's current position is a valid location to spawn this entity. 2215 */ 2216 public boolean getCanSpawnHere() 2217 { 2218 return this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox); 2219 } 2220 2221 /** 2222 * sets the dead flag. Used when you fall off the bottom of the world. 2223 */ 2224 protected void kill() 2225 { 2226 this.attackEntityFrom(DamageSource.outOfWorld, 4); 2227 } 2228 2229 @SideOnly(Side.CLIENT) 2230 2231 /** 2232 * Returns where in the swing animation the living entity is (from 0 to 1). Args: partialTickTime 2233 */ 2234 public float getSwingProgress(float par1) 2235 { 2236 float var2 = this.swingProgress - this.prevSwingProgress; 2237 2238 if (var2 < 0.0F) 2239 { 2240 ++var2; 2241 } 2242 2243 return this.prevSwingProgress + var2 * par1; 2244 } 2245 2246 @SideOnly(Side.CLIENT) 2247 2248 /** 2249 * interpolated position vector 2250 */ 2251 public Vec3 getPosition(float par1) 2252 { 2253 if (par1 == 1.0F) 2254 { 2255 return this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ); 2256 } 2257 else 2258 { 2259 double var2 = this.prevPosX + (this.posX - this.prevPosX) * (double)par1; 2260 double var4 = this.prevPosY + (this.posY - this.prevPosY) * (double)par1; 2261 double var6 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double)par1; 2262 return this.worldObj.getWorldVec3Pool().getVecFromPool(var2, var4, var6); 2263 } 2264 } 2265 2266 /** 2267 * returns a (normalized) vector of where this entity is looking 2268 */ 2269 public Vec3 getLookVec() 2270 { 2271 return this.getLook(1.0F); 2272 } 2273 2274 /** 2275 * interpolated look vector 2276 */ 2277 public Vec3 getLook(float par1) 2278 { 2279 float var2; 2280 float var3; 2281 float var4; 2282 float var5; 2283 2284 if (par1 == 1.0F) 2285 { 2286 var2 = MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI); 2287 var3 = MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI); 2288 var4 = -MathHelper.cos(-this.rotationPitch * 0.017453292F); 2289 var5 = MathHelper.sin(-this.rotationPitch * 0.017453292F); 2290 return this.worldObj.getWorldVec3Pool().getVecFromPool((double)(var3 * var4), (double)var5, (double)(var2 * var4)); 2291 } 2292 else 2293 { 2294 var2 = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * par1; 2295 var3 = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * par1; 2296 var4 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI); 2297 var5 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI); 2298 float var6 = -MathHelper.cos(-var2 * 0.017453292F); 2299 float var7 = MathHelper.sin(-var2 * 0.017453292F); 2300 return this.worldObj.getWorldVec3Pool().getVecFromPool((double)(var5 * var6), (double)var7, (double)(var4 * var6)); 2301 } 2302 } 2303 2304 @SideOnly(Side.CLIENT) 2305 2306 /** 2307 * Returns render size modifier 2308 */ 2309 public float getRenderSizeModifier() 2310 { 2311 return 1.0F; 2312 } 2313 2314 @SideOnly(Side.CLIENT) 2315 2316 /** 2317 * Performs a ray trace for the distance specified and using the partial tick time. Args: distance, partialTickTime 2318 */ 2319 public MovingObjectPosition rayTrace(double par1, float par3) 2320 { 2321 Vec3 var4 = this.getPosition(par3); 2322 Vec3 var5 = this.getLook(par3); 2323 Vec3 var6 = var4.addVector(var5.xCoord * par1, var5.yCoord * par1, var5.zCoord * par1); 2324 return this.worldObj.rayTraceBlocks(var4, var6); 2325 } 2326 2327 /** 2328 * Will return how many at most can spawn in a chunk at once. 2329 */ 2330 public int getMaxSpawnedInChunk() 2331 { 2332 return 4; 2333 } 2334 2335 @SideOnly(Side.CLIENT) 2336 public void handleHealthUpdate(byte par1) 2337 { 2338 if (par1 == 2) 2339 { 2340 this.legYaw = 1.5F; 2341 this.hurtResistantTime = this.maxHurtResistantTime; 2342 this.hurtTime = this.maxHurtTime = 10; 2343 this.attackedAtYaw = 0.0F; 2344 this.playSound(this.getHurtSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); 2345 this.attackEntityFrom(DamageSource.generic, 0); 2346 } 2347 else if (par1 == 3) 2348 { 2349 this.playSound(this.getDeathSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); 2350 this.health = 0; 2351 this.onDeath(DamageSource.generic); 2352 } 2353 else 2354 { 2355 super.handleHealthUpdate(par1); 2356 } 2357 } 2358 2359 /** 2360 * Returns whether player is sleeping or not 2361 */ 2362 public boolean isPlayerSleeping() 2363 { 2364 return false; 2365 } 2366 2367 @SideOnly(Side.CLIENT) 2368 2369 /** 2370 * Gets the Icon Index of the item currently held 2371 */ 2372 public int getItemIcon(ItemStack par1ItemStack, int par2) 2373 { 2374 return par1ItemStack.getIconIndex(); 2375 } 2376 2377 protected void updatePotionEffects() 2378 { 2379 Iterator var1 = this.activePotionsMap.keySet().iterator(); 2380 2381 while (var1.hasNext()) 2382 { 2383 Integer var2 = (Integer)var1.next(); 2384 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2); 2385 2386 if (!var3.onUpdate(this)) 2387 { 2388 if (!this.worldObj.isRemote) 2389 { 2390 var1.remove(); 2391 this.onFinishedPotionEffect(var3); 2392 } 2393 } 2394 else if (var3.getDuration() % 600 == 0) 2395 { 2396 this.onChangedPotionEffect(var3); 2397 } 2398 } 2399 2400 int var11; 2401 2402 if (this.potionsNeedUpdate) 2403 { 2404 if (!this.worldObj.isRemote) 2405 { 2406 if (this.activePotionsMap.isEmpty()) 2407 { 2408 this.dataWatcher.updateObject(9, Byte.valueOf((byte)0)); 2409 this.dataWatcher.updateObject(8, Integer.valueOf(0)); 2410 this.setHasActivePotion(false); 2411 } 2412 else 2413 { 2414 var11 = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values()); 2415 this.dataWatcher.updateObject(9, Byte.valueOf((byte)(PotionHelper.func_82817_b(this.activePotionsMap.values()) ? 1 : 0))); 2416 this.dataWatcher.updateObject(8, Integer.valueOf(var11)); 2417 this.setHasActivePotion(this.isPotionActive(Potion.invisibility.id)); 2418 } 2419 } 2420 2421 this.potionsNeedUpdate = false; 2422 } 2423 2424 var11 = this.dataWatcher.getWatchableObjectInt(8); 2425 boolean var12 = this.dataWatcher.getWatchableObjectByte(9) > 0; 2426 2427 if (var11 > 0) 2428 { 2429 boolean var4 = false; 2430 2431 if (!this.getHasActivePotion()) 2432 { 2433 var4 = this.rand.nextBoolean(); 2434 } 2435 else 2436 { 2437 var4 = this.rand.nextInt(15) == 0; 2438 } 2439 2440 if (var12) 2441 { 2442 var4 &= this.rand.nextInt(5) == 0; 2443 } 2444 2445 if (var4 && var11 > 0) 2446 { 2447 double var5 = (double)(var11 >> 16 & 255) / 255.0D; 2448 double var7 = (double)(var11 >> 8 & 255) / 255.0D; 2449 double var9 = (double)(var11 >> 0 & 255) / 255.0D; 2450 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); 2451 } 2452 } 2453 } 2454 2455 public void clearActivePotions() 2456 { 2457 Iterator var1 = this.activePotionsMap.keySet().iterator(); 2458 2459 while (var1.hasNext()) 2460 { 2461 Integer var2 = (Integer)var1.next(); 2462 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2); 2463 2464 if (!this.worldObj.isRemote) 2465 { 2466 var1.remove(); 2467 this.onFinishedPotionEffect(var3); 2468 } 2469 } 2470 } 2471 2472 public Collection getActivePotionEffects() 2473 { 2474 return this.activePotionsMap.values(); 2475 } 2476 2477 public boolean isPotionActive(int par1) 2478 { 2479 return this.activePotionsMap.containsKey(Integer.valueOf(par1)); 2480 } 2481 2482 public boolean isPotionActive(Potion par1Potion) 2483 { 2484 return this.activePotionsMap.containsKey(Integer.valueOf(par1Potion.id)); 2485 } 2486 2487 /** 2488 * returns the PotionEffect for the supplied Potion if it is active, null otherwise. 2489 */ 2490 public PotionEffect getActivePotionEffect(Potion par1Potion) 2491 { 2492 return (PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1Potion.id)); 2493 } 2494 2495 /** 2496 * adds a PotionEffect to the entity 2497 */ 2498 public void addPotionEffect(PotionEffect par1PotionEffect) 2499 { 2500 if (this.isPotionApplicable(par1PotionEffect)) 2501 { 2502 if (this.activePotionsMap.containsKey(Integer.valueOf(par1PotionEffect.getPotionID()))) 2503 { 2504 ((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))).combine(par1PotionEffect); 2505 this.onChangedPotionEffect((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))); 2506 } 2507 else 2508 { 2509 this.activePotionsMap.put(Integer.valueOf(par1PotionEffect.getPotionID()), par1PotionEffect); 2510 this.onNewPotionEffect(par1PotionEffect); 2511 } 2512 } 2513 } 2514 2515 public boolean isPotionApplicable(PotionEffect par1PotionEffect) 2516 { 2517 if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) 2518 { 2519 int var2 = par1PotionEffect.getPotionID(); 2520 2521 if (var2 == Potion.regeneration.id || var2 == Potion.poison.id) 2522 { 2523 return false; 2524 } 2525 } 2526 2527 return true; 2528 } 2529 2530 /** 2531 * Returns true if this entity is undead. 2532 */ 2533 public boolean isEntityUndead() 2534 { 2535 return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD; 2536 } 2537 2538 /** 2539 * Remove the speified potion effect from this entity. 2540 */ 2541 public void removePotionEffectClient(int par1) 2542 { 2543 this.activePotionsMap.remove(Integer.valueOf(par1)); 2544 } 2545 2546 /** 2547 * Remove the specified potion effect from this entity. 2548 */ 2549 public void removePotionEffect(int par1) 2550 { 2551 PotionEffect var2 = (PotionEffect)this.activePotionsMap.remove(Integer.valueOf(par1)); 2552 2553 if (var2 != null) 2554 { 2555 this.onFinishedPotionEffect(var2); 2556 } 2557 } 2558 2559 protected void onNewPotionEffect(PotionEffect par1PotionEffect) 2560 { 2561 this.potionsNeedUpdate = true; 2562 } 2563 2564 protected void onChangedPotionEffect(PotionEffect par1PotionEffect) 2565 { 2566 this.potionsNeedUpdate = true; 2567 } 2568 2569 protected void onFinishedPotionEffect(PotionEffect par1PotionEffect) 2570 { 2571 this.potionsNeedUpdate = true; 2572 } 2573 2574 /** 2575 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown 2576 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities. 2577 */ 2578 public float getSpeedModifier() 2579 { 2580 float var1 = 1.0F; 2581 2582 if (this.isPotionActive(Potion.moveSpeed)) 2583 { 2584 var1 *= 1.0F + 0.2F * (float)(this.getActivePotionEffect(Potion.moveSpeed).getAmplifier() + 1); 2585 } 2586 2587 if (this.isPotionActive(Potion.moveSlowdown)) 2588 { 2589 var1 *= 1.0F - 0.15F * (float)(this.getActivePotionEffect(Potion.moveSlowdown).getAmplifier() + 1); 2590 } 2591 2592 return var1; 2593 } 2594 2595 /** 2596 * Move the entity to the coordinates informed, but keep yaw/pitch values. 2597 */ 2598 public void setPositionAndUpdate(double par1, double par3, double par5) 2599 { 2600 this.setLocationAndAngles(par1, par3, par5, this.rotationYaw, this.rotationPitch); 2601 } 2602 2603 /** 2604 * If Animal, checks if the age timer is negative 2605 */ 2606 public boolean isChild() 2607 { 2608 return false; 2609 } 2610 2611 /** 2612 * Get this Entity's EnumCreatureAttribute 2613 */ 2614 public EnumCreatureAttribute getCreatureAttribute() 2615 { 2616 return EnumCreatureAttribute.UNDEFINED; 2617 } 2618 2619 /** 2620 * Renders broken item particles using the given ItemStack 2621 */ 2622 public void renderBrokenItemStack(ItemStack par1ItemStack) 2623 { 2624 this.playSound("random.break", 0.8F, 0.8F + this.worldObj.rand.nextFloat() * 0.4F); 2625 2626 for (int var2 = 0; var2 < 5; ++var2) 2627 { 2628 Vec3 var3 = this.worldObj.getWorldVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); 2629 var3.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F); 2630 var3.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F); 2631 Vec3 var4 = this.worldObj.getWorldVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D); 2632 var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F); 2633 var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F); 2634 var4 = var4.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ); 2635 this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().itemID, var4.xCoord, var4.yCoord, var4.zCoord, var3.xCoord, var3.yCoord + 0.05D, var3.zCoord); 2636 } 2637 } 2638 2639 public int func_82143_as() 2640 { 2641 if (this.getAttackTarget() == null) 2642 { 2643 return 3; 2644 } 2645 else 2646 { 2647 int var1 = (int)((float)this.health - (float)this.getMaxHealth() * 0.33F); 2648 var1 -= (3 - this.worldObj.difficultySetting) * 4; 2649 2650 if (var1 < 0) 2651 { 2652 var1 = 0; 2653 } 2654 2655 return var1 + 3; 2656 } 2657 } 2658 2659 /** 2660 * Returns the item that this EntityLiving is holding, if any. 2661 */ 2662 public ItemStack getHeldItem() 2663 { 2664 return this.equipment[0]; 2665 } 2666 2667 /** 2668 * 0 = item, 1-n is armor 2669 */ 2670 public ItemStack getCurrentItemOrArmor(int par1) 2671 { 2672 return this.equipment[par1]; 2673 } 2674 2675 public ItemStack getCurrentArmor(int par1) 2676 { 2677 return this.equipment[par1 + 1]; 2678 } 2679 2680 /** 2681 * Sets the held item, or an armor slot. Slot 0 is held item. Slot 1-4 is armor. Params: Item, slot 2682 */ 2683 public void setCurrentItemOrArmor(int par1, ItemStack par2ItemStack) 2684 { 2685 this.equipment[par1] = par2ItemStack; 2686 } 2687 2688 public ItemStack[] getLastActiveItems() 2689 { 2690 return this.equipment; 2691 } 2692 2693 /** 2694 * Drop the equipment for this entity. 2695 */ 2696 protected void dropEquipment(boolean par1, int par2) 2697 { 2698 for (int var3 = 0; var3 < this.getLastActiveItems().length; ++var3) 2699 { 2700 ItemStack var4 = this.getCurrentItemOrArmor(var3); 2701 boolean var5 = this.equipmentDropChances[var3] > 1.0F; 2702 2703 if (var4 != null && (par1 || var5) && this.rand.nextFloat() - (float)par2 * 0.01F < this.equipmentDropChances[var3]) 2704 { 2705 if (!var5 && var4.isItemStackDamageable()) 2706 { 2707 int var6 = Math.max(var4.getMaxDamage() - 25, 1); 2708 int var7 = var4.getMaxDamage() - this.rand.nextInt(this.rand.nextInt(var6) + 1); 2709 2710 if (var7 > var6) 2711 { 2712 var7 = var6; 2713 } 2714 2715 if (var7 < 1) 2716 { 2717 var7 = 1; 2718 } 2719 2720 var4.setItemDamage(var7); 2721 } 2722 2723 this.entityDropItem(var4, 0.0F); 2724 } 2725 } 2726 } 2727 2728 protected void func_82164_bB() 2729 { 2730 if (this.rand.nextFloat() < armorProbability[this.worldObj.difficultySetting]) 2731 { 2732 int var1 = this.rand.nextInt(2); 2733 float var2 = this.worldObj.difficultySetting == 3 ? 0.1F : 0.25F; 2734 2735 if (this.rand.nextFloat() < 0.1F) 2736 { 2737 ++var1; 2738 } 2739 2740 if (this.rand.nextFloat() < 0.1F) 2741 { 2742 ++var1; 2743 } 2744 2745 if (this.rand.nextFloat() < 0.1F) 2746 { 2747 ++var1; 2748 } 2749 2750 for (int var3 = 3; var3 >= 0; --var3) 2751 { 2752 ItemStack var4 = this.getCurrentArmor(var3); 2753 2754 if (var3 < 3 && this.rand.nextFloat() < var2) 2755 { 2756 break; 2757 } 2758 2759 if (var4 == null) 2760 { 2761 Item var5 = getArmorItemForSlot(var3 + 1, var1); 2762 2763 if (var5 != null) 2764 { 2765 this.setCurrentItemOrArmor(var3 + 1, new ItemStack(var5)); 2766 } 2767 } 2768 } 2769 } 2770 } 2771 2772 /** 2773 * Called whenever an item is picked up from walking over it. Args: pickedUpEntity, stackSize 2774 */ 2775 public void onItemPickup(Entity par1Entity, int par2) 2776 { 2777 if (!par1Entity.isDead && !this.worldObj.isRemote) 2778 { 2779 EntityTracker var3 = ((WorldServer)this.worldObj).getEntityTracker(); 2780 2781 if (par1Entity instanceof EntityItem) 2782 { 2783 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2784 } 2785 2786 if (par1Entity instanceof EntityArrow) 2787 { 2788 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2789 } 2790 2791 if (par1Entity instanceof EntityXPOrb) 2792 { 2793 var3.sendPacketToAllPlayersTrackingEntity(par1Entity, new Packet22Collect(par1Entity.entityId, this.entityId)); 2794 } 2795 } 2796 } 2797 2798 public static int func_82159_b(ItemStack par0ItemStack) 2799 { 2800 if (par0ItemStack.itemID != Block.pumpkin.blockID && par0ItemStack.itemID != Item.skull.itemID) 2801 { 2802 if (par0ItemStack.getItem() instanceof ItemArmor) 2803 { 2804 switch (((ItemArmor)par0ItemStack.getItem()).armorType) 2805 { 2806 case 0: 2807 return 4; 2808 case 1: 2809 return 3; 2810 case 2: 2811 return 2; 2812 case 3: 2813 return 1; 2814 } 2815 } 2816 2817 return 0; 2818 } 2819 else 2820 { 2821 return 4; 2822 } 2823 } 2824 2825 /** 2826 * Params: Armor slot, Item tier 2827 */ 2828 public static Item getArmorItemForSlot(int par0, int par1) 2829 { 2830 switch (par0) 2831 { 2832 case 4: 2833 if (par1 == 0) 2834 { 2835 return Item.helmetLeather; 2836 } 2837 else if (par1 == 1) 2838 { 2839 return Item.helmetGold; 2840 } 2841 else if (par1 == 2) 2842 { 2843 return Item.helmetChain; 2844 } 2845 else if (par1 == 3) 2846 { 2847 return Item.helmetSteel; 2848 } 2849 else if (par1 == 4) 2850 { 2851 return Item.helmetDiamond; 2852 } 2853 case 3: 2854 if (par1 == 0) 2855 { 2856 return Item.plateLeather; 2857 } 2858 else if (par1 == 1) 2859 { 2860 return Item.plateGold; 2861 } 2862 else if (par1 == 2) 2863 { 2864 return Item.plateChain; 2865 } 2866 else if (par1 == 3) 2867 { 2868 return Item.plateSteel; 2869 } 2870 else if (par1 == 4) 2871 { 2872 return Item.plateDiamond; 2873 } 2874 case 2: 2875 if (par1 == 0) 2876 { 2877 return Item.legsLeather; 2878 } 2879 else if (par1 == 1) 2880 { 2881 return Item.legsGold; 2882 } 2883 else if (par1 == 2) 2884 { 2885 return Item.legsChain; 2886 } 2887 else if (par1 == 3) 2888 { 2889 return Item.legsSteel; 2890 } 2891 else if (par1 == 4) 2892 { 2893 return Item.legsDiamond; 2894 } 2895 case 1: 2896 if (par1 == 0) 2897 { 2898 return Item.bootsLeather; 2899 } 2900 else if (par1 == 1) 2901 { 2902 return Item.bootsGold; 2903 } 2904 else if (par1 == 2) 2905 { 2906 return Item.bootsChain; 2907 } 2908 else if (par1 == 3) 2909 { 2910 return Item.bootsSteel; 2911 } 2912 else if (par1 == 4) 2913 { 2914 return Item.bootsDiamond; 2915 } 2916 default: 2917 return null; 2918 } 2919 } 2920 2921 protected void func_82162_bC() 2922 { 2923 if (this.getHeldItem() != null && this.rand.nextFloat() < enchantmentProbability[this.worldObj.difficultySetting]) 2924 { 2925 EnchantmentHelper.addRandomEnchantment(this.rand, this.getHeldItem(), 5 + this.worldObj.difficultySetting * this.rand.nextInt(6)); 2926 } 2927 2928 for (int var1 = 0; var1 < 4; ++var1) 2929 { 2930 ItemStack var2 = this.getCurrentArmor(var1); 2931 2932 if (var2 != null && this.rand.nextFloat() < armorEnchantmentProbability[this.worldObj.difficultySetting]) 2933 { 2934 EnchantmentHelper.addRandomEnchantment(this.rand, var2, 5 + this.worldObj.difficultySetting * this.rand.nextInt(6)); 2935 } 2936 } 2937 } 2938 2939 /** 2940 * Initialize this creature. 2941 */ 2942 public void initCreature() {} 2943 2944 /** 2945 * Returns an integer indicating the end point of the swing animation, used by {@link #swingProgress} to provide a 2946 * progress indicator. Takes dig speed enchantments into account. 2947 */ 2948 private int getArmSwingAnimationEnd() 2949 { 2950 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); 2951 } 2952 2953 /** 2954 * Swings the item the player is holding. 2955 */ 2956 public void swingItem() 2957 { 2958 if (!this.isSwingInProgress || this.swingProgressInt >= this.getArmSwingAnimationEnd() / 2 || this.swingProgressInt < 0) 2959 { 2960 this.swingProgressInt = -1; 2961 this.isSwingInProgress = true; 2962 2963 if (this.worldObj instanceof WorldServer) 2964 { 2965 ((WorldServer)this.worldObj).getEntityTracker().sendPacketToAllPlayersTrackingEntity(this, new Packet18Animation(this, 1)); 2966 } 2967 } 2968 } 2969 2970 /** 2971 * returns true if all the conditions for steering the entity are met. For pigs, this is true if it is being ridden 2972 * by a player and the player is holding a carrot-on-a-stick 2973 */ 2974 public boolean canBeSteered() 2975 { 2976 return false; 2977 } 2978 2979 /** 2980 * counts the amount of arrows stuck in the entity. getting hit by arrows increases this, used in rendering 2981 */ 2982 public final int getArrowCountInEntity() 2983 { 2984 return this.dataWatcher.getWatchableObjectByte(10); 2985 } 2986 2987 /** 2988 * sets the amount of arrows stuck in the entity. used for rendering those 2989 */ 2990 public final void setArrowCountInEntity(int par1) 2991 { 2992 this.dataWatcher.updateObject(10, Byte.valueOf((byte)par1)); 2993 } 2994 2995 /*** 2996 * Removes all potion effects that have curativeItem as a curative item for its effect 2997 * @param curativeItem The itemstack we are using to cure potion effects 2998 */ 2999 public void curePotionEffects(ItemStack curativeItem) 3000 { 3001 Iterator<Integer> potionKey = activePotionsMap.keySet().iterator(); 3002 3003 if (worldObj.isRemote) 3004 { 3005 return; 3006 } 3007 3008 while (potionKey.hasNext()) 3009 { 3010 Integer key = potionKey.next(); 3011 PotionEffect effect = (PotionEffect)activePotionsMap.get(key); 3012 3013 if (effect.isCurativeItem(curativeItem)) 3014 { 3015 potionKey.remove(); 3016 onFinishedPotionEffect(effect); 3017 } 3018 } 3019 } 3020 3021 /** 3022 * Returns true if the entity's rider (EntityPlayer) should face forward when mounted. 3023 * currently only used in vanilla code by pigs. 3024 * 3025 * @param player The player who is riding the entity. 3026 * @return If the player should orient the same direction as this entity. 3027 */ 3028 public boolean shouldRiderFaceForward(EntityPlayer player) 3029 { 3030 return this instanceof EntityPig; 3031 } 3032 }