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