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 }