001 package net.minecraft.src;
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.minecraftforge.common.ForgeHooks;
011 import net.minecraftforge.common.MinecraftForge;
012 import net.minecraftforge.event.entity.living.*;
013 import static net.minecraftforge.event.entity.living.LivingEvent.*;
014
015 public abstract class EntityLiving extends Entity
016 {
017 public int maxHurtResistantTime = 20;
018 public float field_70769_ao;
019 public float field_70770_ap;
020 public float renderYawOffset = 0.0F;
021 public float prevRenderYawOffset = 0.0F;
022
023 /** Entity head rotation yaw */
024 public float rotationYawHead = 0.0F;
025
026 /** Entity head rotation yaw at previous tick */
027 public float prevRotationYawHead = 0.0F;
028 protected float field_70768_au;
029 protected float field_70766_av;
030 protected float field_70764_aw;
031 protected float field_70763_ax;
032 protected boolean field_70753_ay = true;
033
034 /** the path for the texture of this entityLiving */
035 protected String texture = "/mob/char.png";
036 protected boolean field_70740_aA = true;
037 protected float field_70741_aB = 0.0F;
038
039 /**
040 * a string holding the type of entity it is currently only implemented in entityPlayer(as 'humanoid')
041 */
042 protected String entityType = null;
043 protected float field_70743_aD = 1.0F;
044
045 /** The score value of the Mob, the amount of points the mob is worth. */
046 protected int scoreValue = 0;
047 protected float field_70745_aF = 0.0F;
048
049 /**
050 * A factor used to determine how far this entity will move each tick if it is walking on land. Adjusted by speed,
051 * and slipperiness of the current block.
052 */
053 public float landMovementFactor = 0.1F;
054
055 /**
056 * A factor used to determine how far this entity will move each tick if it is jumping or falling.
057 */
058 public float jumpMovementFactor = 0.02F;
059 public float prevSwingProgress;
060 public float swingProgress;
061 protected int health = this.getMaxHealth();
062 public int prevHealth;
063
064 /**
065 * in each step in the damage calculations, this is set to the 'carryover' that would result if someone was damaged
066 * .25 hearts (for example), and added to the damage in the next step
067 */
068 public int carryoverDamage;
069
070 /** Number of ticks since this EntityLiving last produced its sound */
071 private int livingSoundTime;
072
073 /**
074 * The amount of time remaining this entity should act 'hurt'. (Visual appearance of red tint)
075 */
076 public int hurtTime;
077
078 /** What the hurt time was max set to last. */
079 public int maxHurtTime;
080
081 /** The yaw at which this entity was last attacked from. */
082 public float attackedAtYaw = 0.0F;
083
084 /**
085 * The amount of time remaining this entity should act 'dead', i.e. have a corpse in the world.
086 */
087 public int deathTime = 0;
088 public int attackTime = 0;
089 public float prevCameraPitch;
090 public float cameraPitch;
091
092 /**
093 * This gets set on entity death, but never used. Looks like a duplicate of isDead
094 */
095 protected boolean dead = false;
096
097 /** The experience points the Entity gives. */
098 protected int experienceValue;
099 public int field_70731_aW = -1;
100 public float field_70730_aX = (float)(Math.random() * 0.8999999761581421D + 0.10000000149011612D);
101 public float prevLegYaw;
102 public float legYaw;
103
104 /**
105 * Only relevant when legYaw is not 0(the entity is moving). Influences where in its swing legs and arms currently
106 * are.
107 */
108 public float legSwing;
109
110 /** The most recent player that has attacked this entity */
111 protected EntityPlayer attackingPlayer = null;
112
113 /**
114 * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity
115 * should drop items on death.
116 */
117 protected int recentlyHit = 0;
118
119 /** is only being set, has no uses as of MC 1.1 */
120 private EntityLiving entityLivingToAttack = null;
121 private int revengeTimer = 0;
122 private EntityLiving lastAttackingEntity = null;
123
124 /**
125 * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity
126 * should drop items on death.
127 */
128 public int arrowHitTempCounter = 0;
129 public int arrowHitTimer = 0;
130 protected HashMap activePotionsMap = new HashMap();
131
132 /** Whether the DataWatcher needs to be updated with the active potions */
133 private boolean potionsNeedUpdate = true;
134 private int field_70748_f;
135 private EntityLookHelper lookHelper;
136 private EntityMoveHelper moveHelper;
137
138 /** Entity jumping helper */
139 private EntityJumpHelper jumpHelper;
140 private EntityBodyHelper bodyHelper;
141 private PathNavigate navigator;
142 public final EntityAITasks tasks;
143 protected final EntityAITasks targetTasks;
144
145 /** The active target the Task system uses for tracking */
146 private EntityLiving attackTarget;
147 private EntitySenses senses;
148 private float AIMoveSpeed;
149 private ChunkCoordinates homePosition = new ChunkCoordinates(0, 0, 0);
150
151 /** If -1 there is no maximum distance */
152 private float maximumHomeDistance = -1.0F;
153
154 /**
155 * The number of updates over which the new position and rotation are to be applied to the entity.
156 */
157 protected int newPosRotationIncrements;
158
159 /** The new X position to be applied to the entity. */
160 protected double newPosX;
161
162 /** The new Y position to be applied to the entity. */
163 protected double newPosY;
164
165 /** The new Z position to be applied to the entity. */
166 protected double newPosZ;
167
168 /** The new yaw rotation to be applied to the entity. */
169 protected double newRotationYaw;
170
171 /** The new yaw rotation to be applied to the entity. */
172 protected double newRotationPitch;
173 float field_70706_bo = 0.0F;
174
175 /** Amount of damage taken in last hit, in half-hearts */
176 protected int lastDamage = 0;
177
178 /** Holds the living entity age, used to control the despawn. */
179 protected int entityAge = 0;
180 protected float moveStrafing;
181 protected float moveForward;
182 protected float randomYawVelocity;
183
184 /** used to check whether entity is jumping. */
185 public boolean isJumping = false;
186 protected float defaultPitch = 0.0F;
187 protected float moveSpeed = 0.7F;
188
189 /** Number of ticks since last jump */
190 private int jumpTicks = 0;
191
192 /** This entity's current target. */
193 private Entity currentTarget;
194
195 /** How long to keep a specific target entity */
196 protected int numTicksToChaseTarget = 0;
197
198 public EntityLiving(World par1World)
199 {
200 super(par1World);
201 this.preventEntitySpawning = true;
202 this.tasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
203 this.targetTasks = new EntityAITasks(par1World != null && par1World.theProfiler != null ? par1World.theProfiler : null);
204 this.lookHelper = new EntityLookHelper(this);
205 this.moveHelper = new EntityMoveHelper(this);
206 this.jumpHelper = new EntityJumpHelper(this);
207 this.bodyHelper = new EntityBodyHelper(this);
208 this.navigator = new PathNavigate(this, par1World, 16.0F);
209 this.senses = new EntitySenses(this);
210 this.field_70770_ap = (float)(Math.random() + 1.0D) * 0.01F;
211 this.setPosition(this.posX, this.posY, this.posZ);
212 this.field_70769_ao = (float)Math.random() * 12398.0F;
213 this.rotationYaw = (float)(Math.random() * Math.PI * 2.0D);
214 this.rotationYawHead = this.rotationYaw;
215 this.stepHeight = 0.5F;
216 }
217
218 public EntityLookHelper getLookHelper()
219 {
220 return this.lookHelper;
221 }
222
223 public EntityMoveHelper getMoveHelper()
224 {
225 return this.moveHelper;
226 }
227
228 public EntityJumpHelper getJumpHelper()
229 {
230 return this.jumpHelper;
231 }
232
233 public PathNavigate getNavigator()
234 {
235 return this.navigator;
236 }
237
238 /**
239 * returns the EntitySenses Object for the EntityLiving
240 */
241 public EntitySenses getEntitySenses()
242 {
243 return this.senses;
244 }
245
246 public Random getRNG()
247 {
248 return this.rand;
249 }
250
251 public EntityLiving getAITarget()
252 {
253 return this.entityLivingToAttack;
254 }
255
256 public EntityLiving getLastAttackingEntity()
257 {
258 return this.lastAttackingEntity;
259 }
260
261 public void setLastAttackingEntity(Entity par1Entity)
262 {
263 if (par1Entity instanceof EntityLiving)
264 {
265 this.lastAttackingEntity = (EntityLiving)par1Entity;
266 }
267 }
268
269 public int getAge()
270 {
271 return this.entityAge;
272 }
273
274 public float func_70079_am()
275 {
276 return this.rotationYawHead;
277 }
278
279 @SideOnly(Side.CLIENT)
280
281 /**
282 * Sets the head's yaw rotation of the entity.
283 */
284 public void setHeadRotationYaw(float par1)
285 {
286 this.rotationYawHead = par1;
287 }
288
289 /**
290 * the movespeed used for the new AI system
291 */
292 public float getAIMoveSpeed()
293 {
294 return this.AIMoveSpeed;
295 }
296
297 /**
298 * set the movespeed used for the new AI system
299 */
300 public void setAIMoveSpeed(float par1)
301 {
302 this.AIMoveSpeed = par1;
303 this.setMoveForward(par1);
304 }
305
306 public boolean attackEntityAsMob(Entity par1Entity)
307 {
308 this.setLastAttackingEntity(par1Entity);
309 return false;
310 }
311
312 /**
313 * Gets the active target the Task system uses for tracking
314 */
315 public EntityLiving getAttackTarget()
316 {
317 return this.attackTarget;
318 }
319
320 /**
321 * Sets the active target the Task system uses for tracking
322 */
323 public void setAttackTarget(EntityLiving par1EntityLiving)
324 {
325 this.attackTarget = par1EntityLiving;
326 ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
327 }
328
329 public boolean isExplosiveMob(Class par1Class)
330 {
331 return EntityCreeper.class != par1Class && EntityGhast.class != par1Class;
332 }
333
334 /**
335 * This function applies the benefits of growing back wool and faster growing up to the acting entity. (This
336 * function is used in the AIEatGrass)
337 */
338 public void eatGrassBonus() {}
339
340 /**
341 * Returns true if entity is within home distance from current position
342 */
343 public boolean isWithinHomeDistanceCurrentPosition()
344 {
345 return this.isWithinHomeDistance(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
346 }
347
348 public boolean isWithinHomeDistance(int par1, int par2, int par3)
349 {
350 return this.maximumHomeDistance == -1.0F ? true : this.homePosition.getDistanceSquared(par1, par2, par3) < this.maximumHomeDistance * this.maximumHomeDistance;
351 }
352
353 public void setHomeArea(int par1, int par2, int par3, int par4)
354 {
355 this.homePosition.set(par1, par2, par3);
356 this.maximumHomeDistance = (float)par4;
357 }
358
359 public ChunkCoordinates getHomePosition()
360 {
361 return this.homePosition;
362 }
363
364 public float getMaximumHomeDistance()
365 {
366 return this.maximumHomeDistance;
367 }
368
369 public void detachHome()
370 {
371 this.maximumHomeDistance = -1.0F;
372 }
373
374 public boolean hasHome()
375 {
376 return this.maximumHomeDistance != -1.0F;
377 }
378
379 public void setRevengeTarget(EntityLiving par1EntityLiving)
380 {
381 this.entityLivingToAttack = par1EntityLiving;
382 this.revengeTimer = this.entityLivingToAttack != null ? 60 : 0;
383 ForgeHooks.onLivingSetAttackTarget(this, par1EntityLiving);
384 }
385
386 protected void entityInit()
387 {
388 this.dataWatcher.addObject(8, Integer.valueOf(this.field_70748_f));
389 }
390
391 /**
392 * returns true if the entity provided in the argument can be seen. (Raytrace)
393 */
394 public boolean canEntityBeSeen(Entity par1Entity)
395 {
396 return this.worldObj.rayTraceBlocks(Vec3.getVec3Pool().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ), Vec3.getVec3Pool().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null;
397 }
398
399 @SideOnly(Side.CLIENT)
400
401 /**
402 * Returns the texture's file path as a String.
403 */
404 public String getTexture()
405 {
406 return this.texture;
407 }
408
409 /**
410 * Returns true if other Entities should be prevented from moving through this Entity.
411 */
412 public boolean canBeCollidedWith()
413 {
414 return !this.isDead;
415 }
416
417 /**
418 * Returns true if this entity should push and be pushed by other entities when colliding.
419 */
420 public boolean canBePushed()
421 {
422 return !this.isDead;
423 }
424
425 public float getEyeHeight()
426 {
427 return this.height * 0.85F;
428 }
429
430 /**
431 * Get number of ticks, at least during which the living entity will be silent.
432 */
433 public int getTalkInterval()
434 {
435 return 80;
436 }
437
438 /**
439 * Plays living's sound at its position
440 */
441 public void playLivingSound()
442 {
443 String var1 = this.getLivingSound();
444
445 if (var1 != null)
446 {
447 this.worldObj.playSoundAtEntity(this, var1, this.getSoundVolume(), this.getSoundPitch());
448 }
449 }
450
451 /**
452 * Gets called every tick from main Entity class
453 */
454 public void onEntityUpdate()
455 {
456 this.prevSwingProgress = this.swingProgress;
457 super.onEntityUpdate();
458 this.worldObj.theProfiler.startSection("mobBaseTick");
459
460 if (this.isEntityAlive() && this.rand.nextInt(1000) < this.livingSoundTime++)
461 {
462 this.livingSoundTime = -this.getTalkInterval();
463 this.playLivingSound();
464 }
465
466 if (this.isEntityAlive() && this.isEntityInsideOpaqueBlock())
467 {
468 this.attackEntityFrom(DamageSource.inWall, 1);
469 }
470
471 if (this.isImmuneToFire() || this.worldObj.isRemote)
472 {
473 this.extinguish();
474 }
475
476 if (this.isEntityAlive() && this.isInsideOfMaterial(Material.water) && !this.canBreatheUnderwater() && !this.activePotionsMap.containsKey(Integer.valueOf(Potion.waterBreathing.id)))
477 {
478 this.setAir(this.decreaseAirSupply(this.getAir()));
479
480 if (this.getAir() == -20)
481 {
482 this.setAir(0);
483
484 for (int var1 = 0; var1 < 8; ++var1)
485 {
486 float var2 = this.rand.nextFloat() - this.rand.nextFloat();
487 float var3 = this.rand.nextFloat() - this.rand.nextFloat();
488 float var4 = this.rand.nextFloat() - this.rand.nextFloat();
489 this.worldObj.spawnParticle("bubble", this.posX + (double)var2, this.posY + (double)var3, this.posZ + (double)var4, this.motionX, this.motionY, this.motionZ);
490 }
491
492 this.attackEntityFrom(DamageSource.drown, 2);
493 }
494
495 this.extinguish();
496 }
497 else
498 {
499 this.setAir(300);
500 }
501
502 this.prevCameraPitch = this.cameraPitch;
503
504 if (this.attackTime > 0)
505 {
506 --this.attackTime;
507 }
508
509 if (this.hurtTime > 0)
510 {
511 --this.hurtTime;
512 }
513
514 if (this.hurtResistantTime > 0)
515 {
516 --this.hurtResistantTime;
517 }
518
519 if (this.health <= 0)
520 {
521 this.onDeathUpdate();
522 }
523
524 if (this.recentlyHit > 0)
525 {
526 --this.recentlyHit;
527 }
528 else
529 {
530 this.attackingPlayer = null;
531 }
532
533 if (this.lastAttackingEntity != null && !this.lastAttackingEntity.isEntityAlive())
534 {
535 this.lastAttackingEntity = null;
536 }
537
538 if (this.entityLivingToAttack != null)
539 {
540 if (!this.entityLivingToAttack.isEntityAlive())
541 {
542 this.setRevengeTarget((EntityLiving)null);
543 }
544 else if (this.revengeTimer > 0)
545 {
546 --this.revengeTimer;
547 }
548 else
549 {
550 this.setRevengeTarget((EntityLiving)null);
551 }
552 }
553
554 this.updatePotionEffects();
555 this.field_70763_ax = this.field_70764_aw;
556 this.prevRenderYawOffset = this.renderYawOffset;
557 this.prevRotationYawHead = this.rotationYawHead;
558 this.prevRotationYaw = this.rotationYaw;
559 this.prevRotationPitch = this.rotationPitch;
560 this.worldObj.theProfiler.endSection();
561 }
562
563 /**
564 * handles entity death timer, experience orb and particle creation
565 */
566 protected void onDeathUpdate()
567 {
568 ++this.deathTime;
569
570 if (this.deathTime == 20)
571 {
572 int var1;
573
574 if (!this.worldObj.isRemote && (this.recentlyHit > 0 || this.isPlayer()) && !this.isChild())
575 {
576 var1 = this.getExperiencePoints(this.attackingPlayer);
577
578 while (var1 > 0)
579 {
580 int var2 = EntityXPOrb.getXPSplit(var1);
581 var1 -= var2;
582 this.worldObj.spawnEntityInWorld(new EntityXPOrb(this.worldObj, this.posX, this.posY, this.posZ, var2));
583 }
584 }
585
586 this.setDead();
587
588 for (var1 = 0; var1 < 20; ++var1)
589 {
590 double var8 = this.rand.nextGaussian() * 0.02D;
591 double var4 = this.rand.nextGaussian() * 0.02D;
592 double var6 = this.rand.nextGaussian() * 0.02D;
593 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);
594 }
595 }
596 }
597
598 /**
599 * Decrements the entity's air supply when underwater
600 */
601 protected int decreaseAirSupply(int par1)
602 {
603 return par1 - 1;
604 }
605
606 /**
607 * Get the experience points the entity currently has.
608 */
609 protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
610 {
611 return this.experienceValue;
612 }
613
614 /**
615 * Only use is to identify if class is an instance of player for experience dropping
616 */
617 protected boolean isPlayer()
618 {
619 return false;
620 }
621
622 /**
623 * Spawns an explosion particle around the Entity's location
624 */
625 public void spawnExplosionParticle()
626 {
627 for (int var1 = 0; var1 < 20; ++var1)
628 {
629 double var2 = this.rand.nextGaussian() * 0.02D;
630 double var4 = this.rand.nextGaussian() * 0.02D;
631 double var6 = this.rand.nextGaussian() * 0.02D;
632 double var8 = 10.0D;
633 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);
634 }
635 }
636
637 /**
638 * Handles updating while being ridden by an entity
639 */
640 public void updateRidden()
641 {
642 super.updateRidden();
643 this.field_70768_au = this.field_70766_av;
644 this.field_70766_av = 0.0F;
645 this.fallDistance = 0.0F;
646 }
647
648 @SideOnly(Side.CLIENT)
649
650 /**
651 * Sets the position and rotation. Only difference from the other one is no bounding on the rotation. Args: posX,
652 * posY, posZ, yaw, pitch
653 */
654 public void setPositionAndRotation2(double par1, double par3, double par5, float par7, float par8, int par9)
655 {
656 this.yOffset = 0.0F;
657 this.newPosX = par1;
658 this.newPosY = par3;
659 this.newPosZ = par5;
660 this.newRotationYaw = (double)par7;
661 this.newRotationPitch = (double)par8;
662 this.newPosRotationIncrements = par9;
663 }
664
665 /**
666 * Called to update the entity's position/logic.
667 */
668 public void onUpdate()
669 {
670 if (ForgeHooks.onLivingUpdate(this))
671 {
672 return;
673 }
674
675 super.onUpdate();
676
677 if (this.arrowHitTempCounter > 0)
678 {
679 if (this.arrowHitTimer <= 0)
680 {
681 this.arrowHitTimer = 60;
682 }
683
684 --this.arrowHitTimer;
685
686 if (this.arrowHitTimer <= 0)
687 {
688 --this.arrowHitTempCounter;
689 }
690 }
691
692 this.onLivingUpdate();
693 double var1 = this.posX - this.prevPosX;
694 double var3 = this.posZ - this.prevPosZ;
695 float var5 = (float)(var1 * var1 + var3 * var3);
696 float var6 = this.renderYawOffset;
697 float var7 = 0.0F;
698 this.field_70768_au = this.field_70766_av;
699 float var8 = 0.0F;
700
701 if (var5 > 0.0025000002F)
702 {
703 var8 = 1.0F;
704 var7 = (float)Math.sqrt((double)var5) * 3.0F;
705 var6 = (float)Math.atan2(var3, var1) * 180.0F / (float)Math.PI - 90.0F;
706 }
707
708 if (this.swingProgress > 0.0F)
709 {
710 var6 = this.rotationYaw;
711 }
712
713 if (!this.onGround)
714 {
715 var8 = 0.0F;
716 }
717
718 this.field_70766_av += (var8 - this.field_70766_av) * 0.3F;
719 this.worldObj.theProfiler.startSection("headTurn");
720
721 if (this.isAIEnabled())
722 {
723 this.bodyHelper.func_75664_a();
724 }
725 else
726 {
727 float var9 = MathHelper.wrapAngleTo180_float(var6 - this.renderYawOffset);
728 this.renderYawOffset += var9 * 0.3F;
729 float var10 = MathHelper.wrapAngleTo180_float(this.rotationYaw - this.renderYawOffset);
730 boolean var11 = var10 < -90.0F || var10 >= 90.0F;
731
732 if (var10 < -75.0F)
733 {
734 var10 = -75.0F;
735 }
736
737 if (var10 >= 75.0F)
738 {
739 var10 = 75.0F;
740 }
741
742 this.renderYawOffset = this.rotationYaw - var10;
743
744 if (var10 * var10 > 2500.0F)
745 {
746 this.renderYawOffset += var10 * 0.2F;
747 }
748
749 if (var11)
750 {
751 var7 *= -1.0F;
752 }
753 }
754
755 this.worldObj.theProfiler.endSection();
756 this.worldObj.theProfiler.startSection("rangeChecks");
757
758 while (this.rotationYaw - this.prevRotationYaw < -180.0F)
759 {
760 this.prevRotationYaw -= 360.0F;
761 }
762
763 while (this.rotationYaw - this.prevRotationYaw >= 180.0F)
764 {
765 this.prevRotationYaw += 360.0F;
766 }
767
768 while (this.renderYawOffset - this.prevRenderYawOffset < -180.0F)
769 {
770 this.prevRenderYawOffset -= 360.0F;
771 }
772
773 while (this.renderYawOffset - this.prevRenderYawOffset >= 180.0F)
774 {
775 this.prevRenderYawOffset += 360.0F;
776 }
777
778 while (this.rotationPitch - this.prevRotationPitch < -180.0F)
779 {
780 this.prevRotationPitch -= 360.0F;
781 }
782
783 while (this.rotationPitch - this.prevRotationPitch >= 180.0F)
784 {
785 this.prevRotationPitch += 360.0F;
786 }
787
788 while (this.rotationYawHead - this.prevRotationYawHead < -180.0F)
789 {
790 this.prevRotationYawHead -= 360.0F;
791 }
792
793 while (this.rotationYawHead - this.prevRotationYawHead >= 180.0F)
794 {
795 this.prevRotationYawHead += 360.0F;
796 }
797
798 this.worldObj.theProfiler.endSection();
799 this.field_70764_aw += var7;
800 }
801
802 /**
803 * Heal living entity (param: amount of half-hearts)
804 */
805 public void heal(int par1)
806 {
807 if (this.health > 0)
808 {
809 this.health += par1;
810
811 if (this.health > this.getMaxHealth())
812 {
813 this.health = this.getMaxHealth();
814 }
815
816 this.hurtResistantTime = this.maxHurtResistantTime / 2;
817 }
818 }
819
820 public abstract int getMaxHealth();
821
822 public int getHealth()
823 {
824 return this.health;
825 }
826
827 public void setEntityHealth(int par1)
828 {
829 this.health = par1;
830
831 if (par1 > this.getMaxHealth())
832 {
833 par1 = this.getMaxHealth();
834 }
835 }
836
837 /**
838 * Called when the entity is attacked.
839 */
840 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
841 {
842 if (ForgeHooks.onLivingAttack(this, par1DamageSource, par2))
843 {
844 return false;
845 }
846
847 if (this.worldObj.isRemote)
848 {
849 return false;
850 }
851 else
852 {
853 this.entityAge = 0;
854
855 if (this.health <= 0)
856 {
857 return false;
858 }
859 else if (par1DamageSource.fireDamage() && this.isPotionActive(Potion.fireResistance))
860 {
861 return false;
862 }
863 else
864 {
865 this.legYaw = 1.5F;
866 boolean var3 = true;
867
868 if ((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F)
869 {
870 if (par2 <= this.lastDamage)
871 {
872 return false;
873 }
874
875 this.damageEntity(par1DamageSource, par2 - this.lastDamage);
876 this.lastDamage = par2;
877 var3 = false;
878 }
879 else
880 {
881 this.lastDamage = par2;
882 this.prevHealth = this.health;
883 this.hurtResistantTime = this.maxHurtResistantTime;
884 this.damageEntity(par1DamageSource, par2);
885 this.hurtTime = this.maxHurtTime = 10;
886 }
887
888 this.attackedAtYaw = 0.0F;
889 Entity var4 = par1DamageSource.getEntity();
890
891 if (var4 != null)
892 {
893 if (var4 instanceof EntityLiving)
894 {
895 this.setRevengeTarget((EntityLiving)var4);
896 }
897
898 if (var4 instanceof EntityPlayer)
899 {
900 this.recentlyHit = 60;
901 this.attackingPlayer = (EntityPlayer)var4;
902 }
903 else if (var4 instanceof EntityWolf)
904 {
905 EntityWolf var5 = (EntityWolf)var4;
906
907 if (var5.isTamed())
908 {
909 this.recentlyHit = 60;
910 this.attackingPlayer = null;
911 }
912 }
913 }
914
915 if (var3)
916 {
917 this.worldObj.setEntityState(this, (byte)2);
918
919 if (par1DamageSource != DamageSource.drown && par1DamageSource != DamageSource.field_76375_l)
920 {
921 this.setBeenAttacked();
922 }
923
924 if (var4 != null)
925 {
926 double var9 = var4.posX - this.posX;
927 double var7;
928
929 for (var7 = var4.posZ - this.posZ; var9 * var9 + var7 * var7 < 1.0E-4D; var7 = (Math.random() - Math.random()) * 0.01D)
930 {
931 var9 = (Math.random() - Math.random()) * 0.01D;
932 }
933
934 this.attackedAtYaw = (float)(Math.atan2(var7, var9) * 180.0D / Math.PI) - this.rotationYaw;
935 this.knockBack(var4, par2, var9, var7);
936 }
937 else
938 {
939 this.attackedAtYaw = (float)((int)(Math.random() * 2.0D) * 180);
940 }
941 }
942
943 if (this.health <= 0)
944 {
945 if (var3)
946 {
947 this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), this.getSoundPitch());
948 }
949
950 this.onDeath(par1DamageSource);
951 }
952 else if (var3)
953 {
954 this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), this.getSoundPitch());
955 }
956
957 return true;
958 }
959 }
960 }
961
962 /**
963 * Gets the pitch of living sounds in living entities.
964 */
965 private float getSoundPitch()
966 {
967 return this.isChild() ? (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.5F : (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F;
968 }
969
970 @SideOnly(Side.CLIENT)
971
972 /**
973 * Setups the entity to do the hurt animation. Only used by packets in multiplayer.
974 */
975 public void performHurtAnimation()
976 {
977 this.hurtTime = this.maxHurtTime = 10;
978 this.attackedAtYaw = 0.0F;
979 }
980
981 /**
982 * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
983 */
984 public int getTotalArmorValue()
985 {
986 return 0;
987 }
988
989 protected void damageArmor(int par1) {}
990
991 /**
992 * Reduces damage, depending on armor
993 */
994 protected int applyArmorCalculations(DamageSource par1DamageSource, int par2)
995 {
996 if (!par1DamageSource.isUnblockable())
997 {
998 int var3 = 25 - this.getTotalArmorValue();
999 int var4 = par2 * var3 + this.carryoverDamage;
1000 this.damageArmor(par2);
1001 par2 = var4 / 25;
1002 this.carryoverDamage = var4 % 25;
1003 }
1004
1005 return par2;
1006 }
1007
1008 /**
1009 * Reduces damage, depending on potions
1010 */
1011 protected int applyPotionDamageCalculations(DamageSource par1DamageSource, int par2)
1012 {
1013 if (this.isPotionActive(Potion.resistance))
1014 {
1015 int var3 = (this.getActivePotionEffect(Potion.resistance).getAmplifier() + 1) * 5;
1016 int var4 = 25 - var3;
1017 int var5 = par2 * var4 + this.carryoverDamage;
1018 par2 = var5 / 25;
1019 this.carryoverDamage = var5 % 25;
1020 }
1021
1022 return par2;
1023 }
1024
1025 /**
1026 * Deals damage to the entity. If its a EntityPlayer then will take damage from the armor first and then health
1027 * second with the reduced value. Args: damageAmount
1028 */
1029 protected void damageEntity(DamageSource par1DamageSource, int par2)
1030 {
1031 par2 = ForgeHooks.onLivingHurt(this, par1DamageSource, par2);
1032 if (par2 <= 0)
1033 {
1034 return;
1035 }
1036
1037 par2 = this.applyArmorCalculations(par1DamageSource, par2);
1038 par2 = this.applyPotionDamageCalculations(par1DamageSource, par2);
1039 this.health -= par2;
1040 }
1041
1042 /**
1043 * Returns the volume for the sounds this mob makes.
1044 */
1045 protected float getSoundVolume()
1046 {
1047 return 1.0F;
1048 }
1049
1050 /**
1051 * Returns the sound this mob makes while it's alive.
1052 */
1053 protected String getLivingSound()
1054 {
1055 return null;
1056 }
1057
1058 /**
1059 * Returns the sound this mob makes when it is hurt.
1060 */
1061 protected String getHurtSound()
1062 {
1063 return "damage.hurtflesh";
1064 }
1065
1066 /**
1067 * Returns the sound this mob makes on death.
1068 */
1069 protected String getDeathSound()
1070 {
1071 return "damage.hurtflesh";
1072 }
1073
1074 /**
1075 * knocks back this entity
1076 */
1077 public void knockBack(Entity par1Entity, int par2, double par3, double par5)
1078 {
1079 this.isAirBorne = true;
1080 float var7 = MathHelper.sqrt_double(par3 * par3 + par5 * par5);
1081 float var8 = 0.4F;
1082 this.motionX /= 2.0D;
1083 this.motionY /= 2.0D;
1084 this.motionZ /= 2.0D;
1085 this.motionX -= par3 / (double)var7 * (double)var8;
1086 this.motionY += (double)var8;
1087 this.motionZ -= par5 / (double)var7 * (double)var8;
1088
1089 if (this.motionY > 0.4000000059604645D)
1090 {
1091 this.motionY = 0.4000000059604645D;
1092 }
1093 }
1094
1095 /**
1096 * Called when the mob's health reaches 0.
1097 */
1098 public void onDeath(DamageSource par1DamageSource)
1099 {
1100 if (ForgeHooks.onLivingDeath(this, par1DamageSource))
1101 {
1102 return;
1103 }
1104
1105 Entity var2 = par1DamageSource.getEntity();
1106
1107 if (this.scoreValue >= 0 && var2 != null)
1108 {
1109 var2.addToPlayerScore(this, this.scoreValue);
1110 }
1111
1112 if (var2 != null)
1113 {
1114 var2.onKillEntity(this);
1115 }
1116
1117 this.dead = true;
1118
1119 if (!this.worldObj.isRemote)
1120 {
1121 int var3 = 0;
1122
1123 if (var2 instanceof EntityPlayer)
1124 {
1125 var3 = EnchantmentHelper.getLootingModifier(((EntityPlayer)var2).inventory);
1126 }
1127
1128 captureDrops = true;
1129 capturedDrops.clear();
1130 int var4 = 0;
1131
1132 if (!this.isChild())
1133 {
1134 this.dropFewItems(this.recentlyHit > 0, var3);
1135
1136 if (this.recentlyHit > 0)
1137 {
1138 var4 = this.rand.nextInt(200) - var3;
1139
1140 if (var4 < 5)
1141 {
1142 this.dropRareDrop(var4 <= 0 ? 1 : 0);
1143 }
1144 }
1145 }
1146
1147 captureDrops = false;
1148
1149 if (!ForgeHooks.onLivingDrops(this, par1DamageSource, capturedDrops, var3, recentlyHit > 0, var4))
1150 {
1151 for (EntityItem item : capturedDrops)
1152 {
1153 worldObj.spawnEntityInWorld(item);
1154 }
1155 }
1156 }
1157
1158 this.worldObj.setEntityState(this, (byte)3);
1159 }
1160
1161 protected void dropRareDrop(int par1) {}
1162
1163 /**
1164 * Drop 0-2 items of this living's type
1165 */
1166 protected void dropFewItems(boolean par1, int par2)
1167 {
1168 int var3 = this.getDropItemId();
1169
1170 if (var3 > 0)
1171 {
1172 int var4 = this.rand.nextInt(3);
1173
1174 if (par2 > 0)
1175 {
1176 var4 += this.rand.nextInt(par2 + 1);
1177 }
1178
1179 for (int var5 = 0; var5 < var4; ++var5)
1180 {
1181 this.dropItem(var3, 1);
1182 }
1183 }
1184 }
1185
1186 /**
1187 * Returns the item ID for the item the mob drops on death.
1188 */
1189 protected int getDropItemId()
1190 {
1191 return 0;
1192 }
1193
1194 /**
1195 * Called when the mob is falling. Calculates and applies fall damage.
1196 */
1197 protected void fall(float par1)
1198 {
1199 par1 = ForgeHooks.onLivingFall(this, par1);
1200 if (par1 <= 0)
1201 {
1202 return;
1203 }
1204
1205 super.fall(par1);
1206 int var2 = MathHelper.ceiling_float_int(par1 - 3.0F);
1207
1208 if (var2 > 0)
1209 {
1210 if (var2 > 4)
1211 {
1212 this.worldObj.playSoundAtEntity(this, "damage.fallbig", 1.0F, 1.0F);
1213 }
1214 else
1215 {
1216 this.worldObj.playSoundAtEntity(this, "damage.fallsmall", 1.0F, 1.0F);
1217 }
1218
1219 this.attackEntityFrom(DamageSource.fall, var2);
1220 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));
1221
1222 if (var3 > 0)
1223 {
1224 StepSound var4 = Block.blocksList[var3].stepSound;
1225 this.worldObj.playSoundAtEntity(this, var4.getStepSound(), var4.getVolume() * 0.5F, var4.getPitch() * 0.75F);
1226 }
1227 }
1228 }
1229
1230 /**
1231 * Moves the entity based on the specified heading. Args: strafe, forward
1232 */
1233 public void moveEntityWithHeading(float par1, float par2)
1234 {
1235 double var9;
1236
1237 if (this.isInWater() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1238 {
1239 var9 = this.posY;
1240 this.moveFlying(par1, par2, this.isAIEnabled() ? 0.04F : 0.02F);
1241 this.moveEntity(this.motionX, this.motionY, this.motionZ);
1242 this.motionX *= 0.800000011920929D;
1243 this.motionY *= 0.800000011920929D;
1244 this.motionZ *= 0.800000011920929D;
1245 this.motionY -= 0.02D;
1246
1247 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1248 {
1249 this.motionY = 0.30000001192092896D;
1250 }
1251 }
1252 else if (this.handleLavaMovement() && (!(this instanceof EntityPlayer) || !((EntityPlayer)this).capabilities.isFlying))
1253 {
1254 var9 = this.posY;
1255 this.moveFlying(par1, par2, 0.02F);
1256 this.moveEntity(this.motionX, this.motionY, this.motionZ);
1257 this.motionX *= 0.5D;
1258 this.motionY *= 0.5D;
1259 this.motionZ *= 0.5D;
1260 this.motionY -= 0.02D;
1261
1262 if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + var9, this.motionZ))
1263 {
1264 this.motionY = 0.30000001192092896D;
1265 }
1266 }
1267 else
1268 {
1269 float var3 = 0.91F;
1270
1271 if (this.onGround)
1272 {
1273 var3 = 0.54600006F;
1274 int var4 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1275
1276 if (var4 > 0)
1277 {
1278 var3 = Block.blocksList[var4].slipperiness * 0.91F;
1279 }
1280 }
1281
1282 float var8 = 0.16277136F / (var3 * var3 * var3);
1283 float var5;
1284
1285 if (this.onGround)
1286 {
1287 if (this.isAIEnabled())
1288 {
1289 var5 = this.getAIMoveSpeed();
1290 }
1291 else
1292 {
1293 var5 = this.landMovementFactor;
1294 }
1295
1296 var5 *= var8;
1297 }
1298 else
1299 {
1300 var5 = this.jumpMovementFactor;
1301 }
1302
1303 this.moveFlying(par1, par2, var5);
1304 var3 = 0.91F;
1305
1306 if (this.onGround)
1307 {
1308 var3 = 0.54600006F;
1309 int var6 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
1310
1311 if (var6 > 0)
1312 {
1313 var3 = Block.blocksList[var6].slipperiness * 0.91F;
1314 }
1315 }
1316
1317 if (this.isOnLadder())
1318 {
1319 float var10 = 0.15F;
1320
1321 if (this.motionX < (double)(-var10))
1322 {
1323 this.motionX = (double)(-var10);
1324 }
1325
1326 if (this.motionX > (double)var10)
1327 {
1328 this.motionX = (double)var10;
1329 }
1330
1331 if (this.motionZ < (double)(-var10))
1332 {
1333 this.motionZ = (double)(-var10);
1334 }
1335
1336 if (this.motionZ > (double)var10)
1337 {
1338 this.motionZ = (double)var10;
1339 }
1340
1341 this.fallDistance = 0.0F;
1342
1343 if (this.motionY < -0.15D)
1344 {
1345 this.motionY = -0.15D;
1346 }
1347
1348 boolean var7 = this.isSneaking() && this instanceof EntityPlayer;
1349
1350 if (var7 && this.motionY < 0.0D)
1351 {
1352 this.motionY = 0.0D;
1353 }
1354 }
1355
1356 this.moveEntity(this.motionX, this.motionY, this.motionZ);
1357
1358 if (this.isCollidedHorizontally && this.isOnLadder())
1359 {
1360 this.motionY = 0.2D;
1361 }
1362
1363 this.motionY -= 0.08D;
1364 this.motionY *= 0.9800000190734863D;
1365 this.motionX *= (double)var3;
1366 this.motionZ *= (double)var3;
1367 }
1368
1369 this.prevLegYaw = this.legYaw;
1370 var9 = this.posX - this.prevPosX;
1371 double var12 = this.posZ - this.prevPosZ;
1372 float var11 = MathHelper.sqrt_double(var9 * var9 + var12 * var12) * 4.0F;
1373
1374 if (var11 > 1.0F)
1375 {
1376 var11 = 1.0F;
1377 }
1378
1379 this.legYaw += (var11 - this.legYaw) * 0.4F;
1380 this.legSwing += this.legYaw;
1381 }
1382
1383 /**
1384 * returns true if this entity is by a ladder, false otherwise
1385 */
1386 public boolean isOnLadder()
1387 {
1388 int var1 = MathHelper.floor_double(this.posX);
1389 int var2 = MathHelper.floor_double(this.boundingBox.minY);
1390 int var3 = MathHelper.floor_double(this.posZ);
1391 int var4 = this.worldObj.getBlockId(var1, var2, var3);
1392 return ForgeHooks.isLivingOnLadder(Block.blocksList[var4], worldObj, var1, var2, var3);
1393 }
1394
1395 /**
1396 * (abstract) Protected helper method to write subclass entity data to NBT.
1397 */
1398 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
1399 {
1400 par1NBTTagCompound.setShort("Health", (short)this.health);
1401 par1NBTTagCompound.setShort("HurtTime", (short)this.hurtTime);
1402 par1NBTTagCompound.setShort("DeathTime", (short)this.deathTime);
1403 par1NBTTagCompound.setShort("AttackTime", (short)this.attackTime);
1404
1405 if (!this.activePotionsMap.isEmpty())
1406 {
1407 NBTTagList var2 = new NBTTagList();
1408 Iterator var3 = this.activePotionsMap.values().iterator();
1409
1410 while (var3.hasNext())
1411 {
1412 PotionEffect var4 = (PotionEffect)var3.next();
1413 NBTTagCompound var5 = new NBTTagCompound();
1414 var5.setByte("Id", (byte)var4.getPotionID());
1415 var5.setByte("Amplifier", (byte)var4.getAmplifier());
1416 var5.setInteger("Duration", var4.getDuration());
1417 var2.appendTag(var5);
1418 }
1419
1420 par1NBTTagCompound.setTag("ActiveEffects", var2);
1421 }
1422 }
1423
1424 /**
1425 * (abstract) Protected helper method to read subclass entity data from NBT.
1426 */
1427 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
1428 {
1429 if (this.health < -32768)
1430 {
1431 this.health = -32768;
1432 }
1433
1434 this.health = par1NBTTagCompound.getShort("Health");
1435
1436 if (!par1NBTTagCompound.hasKey("Health"))
1437 {
1438 this.health = this.getMaxHealth();
1439 }
1440
1441 this.hurtTime = par1NBTTagCompound.getShort("HurtTime");
1442 this.deathTime = par1NBTTagCompound.getShort("DeathTime");
1443 this.attackTime = par1NBTTagCompound.getShort("AttackTime");
1444
1445 if (par1NBTTagCompound.hasKey("ActiveEffects"))
1446 {
1447 NBTTagList var2 = par1NBTTagCompound.getTagList("ActiveEffects");
1448
1449 for (int var3 = 0; var3 < var2.tagCount(); ++var3)
1450 {
1451 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
1452 byte var5 = var4.getByte("Id");
1453 byte var6 = var4.getByte("Amplifier");
1454 int var7 = var4.getInteger("Duration");
1455 this.activePotionsMap.put(Integer.valueOf(var5), new PotionEffect(var5, var7, var6));
1456 }
1457 }
1458 }
1459
1460 /**
1461 * Checks whether target entity is alive.
1462 */
1463 public boolean isEntityAlive()
1464 {
1465 return !this.isDead && this.health > 0;
1466 }
1467
1468 public boolean canBreatheUnderwater()
1469 {
1470 return false;
1471 }
1472
1473 public void setMoveForward(float par1)
1474 {
1475 this.moveForward = par1;
1476 }
1477
1478 public void setJumping(boolean par1)
1479 {
1480 this.isJumping = par1;
1481 }
1482
1483 /**
1484 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
1485 * use this to react to sunlight and start to burn.
1486 */
1487 public void onLivingUpdate()
1488 {
1489 if (this.jumpTicks > 0)
1490 {
1491 --this.jumpTicks;
1492 }
1493
1494 if (this.newPosRotationIncrements > 0)
1495 {
1496 double var1 = this.posX + (this.newPosX - this.posX) / (double)this.newPosRotationIncrements;
1497 double var3 = this.posY + (this.newPosY - this.posY) / (double)this.newPosRotationIncrements;
1498 double var5 = this.posZ + (this.newPosZ - this.posZ) / (double)this.newPosRotationIncrements;
1499 double var7 = MathHelper.wrapAngleTo180_double(this.newRotationYaw - (double)this.rotationYaw);
1500 this.rotationYaw = (float)((double)this.rotationYaw + var7 / (double)this.newPosRotationIncrements);
1501 this.rotationPitch = (float)((double)this.rotationPitch + (this.newRotationPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements);
1502 --this.newPosRotationIncrements;
1503 this.setPosition(var1, var3, var5);
1504 this.setRotation(this.rotationYaw, this.rotationPitch);
1505 }
1506
1507 if (Math.abs(this.motionX) < 0.005D)
1508 {
1509 this.motionX = 0.0D;
1510 }
1511
1512 if (Math.abs(this.motionY) < 0.005D)
1513 {
1514 this.motionY = 0.0D;
1515 }
1516
1517 if (Math.abs(this.motionZ) < 0.005D)
1518 {
1519 this.motionZ = 0.0D;
1520 }
1521
1522 this.worldObj.theProfiler.startSection("ai");
1523
1524 if (this.isMovementBlocked())
1525 {
1526 this.isJumping = false;
1527 this.moveStrafing = 0.0F;
1528 this.moveForward = 0.0F;
1529 this.randomYawVelocity = 0.0F;
1530 }
1531 else if (this.isClientWorld())
1532 {
1533 if (this.isAIEnabled())
1534 {
1535 this.worldObj.theProfiler.startSection("newAi");
1536 this.updateAITasks();
1537 this.worldObj.theProfiler.endSection();
1538 }
1539 else
1540 {
1541 this.worldObj.theProfiler.startSection("oldAi");
1542 this.updateEntityActionState();
1543 this.worldObj.theProfiler.endSection();
1544 this.rotationYawHead = this.rotationYaw;
1545 }
1546 }
1547
1548 this.worldObj.theProfiler.endSection();
1549 this.worldObj.theProfiler.startSection("jump");
1550
1551 if (this.isJumping)
1552 {
1553 if (!this.isInWater() && !this.handleLavaMovement())
1554 {
1555 if (this.onGround && this.jumpTicks == 0)
1556 {
1557 this.jump();
1558 this.jumpTicks = 10;
1559 }
1560 }
1561 else
1562 {
1563 this.motionY += 0.03999999910593033D;
1564 }
1565 }
1566 else
1567 {
1568 this.jumpTicks = 0;
1569 }
1570
1571 this.worldObj.theProfiler.endSection();
1572 this.worldObj.theProfiler.startSection("travel");
1573 this.moveStrafing *= 0.98F;
1574 this.moveForward *= 0.98F;
1575 this.randomYawVelocity *= 0.9F;
1576 float var9 = this.landMovementFactor;
1577 this.landMovementFactor *= this.getSpeedModifier();
1578 this.moveEntityWithHeading(this.moveStrafing, this.moveForward);
1579 this.landMovementFactor = var9;
1580 this.worldObj.theProfiler.endSection();
1581 this.worldObj.theProfiler.startSection("push");
1582
1583 if (!this.worldObj.isRemote)
1584 {
1585 List var2 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(0.20000000298023224D, 0.0D, 0.20000000298023224D));
1586
1587 if (var2 != null && !var2.isEmpty())
1588 {
1589 Iterator var10 = var2.iterator();
1590
1591 while (var10.hasNext())
1592 {
1593 Entity var4 = (Entity)var10.next();
1594
1595 if (var4.canBePushed())
1596 {
1597 var4.applyEntityCollision(this);
1598 }
1599 }
1600 }
1601 }
1602
1603 this.worldObj.theProfiler.endSection();
1604 }
1605
1606 /**
1607 * Returns true if the newer Entity AI code should be run
1608 */
1609 protected boolean isAIEnabled()
1610 {
1611 return false;
1612 }
1613
1614 /**
1615 * Returns whether the entity is in a local (client) world
1616 */
1617 protected boolean isClientWorld()
1618 {
1619 return !this.worldObj.isRemote;
1620 }
1621
1622 /**
1623 * Dead and sleeping entities cannot move
1624 */
1625 protected boolean isMovementBlocked()
1626 {
1627 return this.health <= 0;
1628 }
1629
1630 public boolean isBlocking()
1631 {
1632 return false;
1633 }
1634
1635 /**
1636 * Causes this entity to do an upwards motion (jumping).
1637 */
1638 protected void jump()
1639 {
1640 this.motionY = 0.41999998688697815D;
1641
1642 if (this.isPotionActive(Potion.jump))
1643 {
1644 this.motionY += (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F);
1645 }
1646
1647 if (this.isSprinting())
1648 {
1649 float var1 = this.rotationYaw * 0.017453292F;
1650 this.motionX -= (double)(MathHelper.sin(var1) * 0.2F);
1651 this.motionZ += (double)(MathHelper.cos(var1) * 0.2F);
1652 }
1653
1654 this.isAirBorne = true;
1655 ForgeHooks.onLivingJump(this);
1656 }
1657
1658 /**
1659 * Determines if an entity can be despawned, used on idle far away entities
1660 */
1661 protected boolean canDespawn()
1662 {
1663 return true;
1664 }
1665
1666 /**
1667 * Makes the entity despawn if requirements are reached
1668 */
1669 protected void despawnEntity()
1670 {
1671 EntityPlayer var1 = this.worldObj.getClosestPlayerToEntity(this, -1.0D);
1672
1673 if (var1 != null)
1674 {
1675 double var2 = var1.posX - this.posX;
1676 double var4 = var1.posY - this.posY;
1677 double var6 = var1.posZ - this.posZ;
1678 double var8 = var2 * var2 + var4 * var4 + var6 * var6;
1679
1680 if (this.canDespawn() && var8 > 16384.0D)
1681 {
1682 this.setDead();
1683 }
1684
1685 if (this.entityAge > 600 && this.rand.nextInt(800) == 0 && var8 > 1024.0D && this.canDespawn())
1686 {
1687 this.setDead();
1688 }
1689 else if (var8 < 1024.0D)
1690 {
1691 this.entityAge = 0;
1692 }
1693 }
1694 }
1695
1696 protected void updateAITasks()
1697 {
1698 ++this.entityAge;
1699 this.worldObj.theProfiler.startSection("checkDespawn");
1700 this.despawnEntity();
1701 this.worldObj.theProfiler.endSection();
1702 this.worldObj.theProfiler.startSection("sensing");
1703 this.senses.clearSensingCache();
1704 this.worldObj.theProfiler.endSection();
1705 this.worldObj.theProfiler.startSection("targetSelector");
1706 this.targetTasks.onUpdateTasks();
1707 this.worldObj.theProfiler.endSection();
1708 this.worldObj.theProfiler.startSection("goalSelector");
1709 this.tasks.onUpdateTasks();
1710 this.worldObj.theProfiler.endSection();
1711 this.worldObj.theProfiler.startSection("navigation");
1712 this.navigator.onUpdateNavigation();
1713 this.worldObj.theProfiler.endSection();
1714 this.worldObj.theProfiler.startSection("mob tick");
1715 this.updateAITick();
1716 this.worldObj.theProfiler.endSection();
1717 this.worldObj.theProfiler.startSection("controls");
1718 this.worldObj.theProfiler.startSection("move");
1719 this.moveHelper.onUpdateMoveHelper();
1720 this.worldObj.theProfiler.endStartSection("look");
1721 this.lookHelper.onUpdateLook();
1722 this.worldObj.theProfiler.endStartSection("jump");
1723 this.jumpHelper.doJump();
1724 this.worldObj.theProfiler.endSection();
1725 this.worldObj.theProfiler.endSection();
1726 }
1727
1728 /**
1729 * main AI tick function, replaces updateEntityActionState
1730 */
1731 protected void updateAITick() {}
1732
1733 protected void updateEntityActionState()
1734 {
1735 ++this.entityAge;
1736 this.despawnEntity();
1737 this.moveStrafing = 0.0F;
1738 this.moveForward = 0.0F;
1739 float var1 = 8.0F;
1740
1741 if (this.rand.nextFloat() < 0.02F)
1742 {
1743 EntityPlayer var2 = this.worldObj.getClosestPlayerToEntity(this, (double)var1);
1744
1745 if (var2 != null)
1746 {
1747 this.currentTarget = var2;
1748 this.numTicksToChaseTarget = 10 + this.rand.nextInt(20);
1749 }
1750 else
1751 {
1752 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
1753 }
1754 }
1755
1756 if (this.currentTarget != null)
1757 {
1758 this.faceEntity(this.currentTarget, 10.0F, (float)this.getVerticalFaceSpeed());
1759
1760 if (this.numTicksToChaseTarget-- <= 0 || this.currentTarget.isDead || this.currentTarget.getDistanceSqToEntity(this) > (double)(var1 * var1))
1761 {
1762 this.currentTarget = null;
1763 }
1764 }
1765 else
1766 {
1767 if (this.rand.nextFloat() < 0.05F)
1768 {
1769 this.randomYawVelocity = (this.rand.nextFloat() - 0.5F) * 20.0F;
1770 }
1771
1772 this.rotationYaw += this.randomYawVelocity;
1773 this.rotationPitch = this.defaultPitch;
1774 }
1775
1776 boolean var4 = this.isInWater();
1777 boolean var3 = this.handleLavaMovement();
1778
1779 if (var4 || var3)
1780 {
1781 this.isJumping = this.rand.nextFloat() < 0.8F;
1782 }
1783 }
1784
1785 /**
1786 * The speed it takes to move the entityliving's rotationPitch through the faceEntity method. This is only currently
1787 * use in wolves.
1788 */
1789 public int getVerticalFaceSpeed()
1790 {
1791 return 40;
1792 }
1793
1794 /**
1795 * Changes pitch and yaw so that the entity calling the function is facing the entity provided as an argument.
1796 */
1797 public void faceEntity(Entity par1Entity, float par2, float par3)
1798 {
1799 double var4 = par1Entity.posX - this.posX;
1800 double var8 = par1Entity.posZ - this.posZ;
1801 double var6;
1802
1803 if (par1Entity instanceof EntityLiving)
1804 {
1805 EntityLiving var10 = (EntityLiving)par1Entity;
1806 var6 = this.posY + (double)this.getEyeHeight() - (var10.posY + (double)var10.getEyeHeight());
1807 }
1808 else
1809 {
1810 var6 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight());
1811 }
1812
1813 double var14 = (double)MathHelper.sqrt_double(var4 * var4 + var8 * var8);
1814 float var12 = (float)(Math.atan2(var8, var4) * 180.0D / Math.PI) - 90.0F;
1815 float var13 = (float)(-(Math.atan2(var6, var14) * 180.0D / Math.PI));
1816 this.rotationPitch = -this.updateRotation(this.rotationPitch, var13, par3);
1817 this.rotationYaw = this.updateRotation(this.rotationYaw, var12, par2);
1818 }
1819
1820 /**
1821 * Arguments: current rotation, intended rotation, max increment.
1822 */
1823 private float updateRotation(float par1, float par2, float par3)
1824 {
1825 float var4 = MathHelper.wrapAngleTo180_float(par2 - par1);
1826
1827 if (var4 > par3)
1828 {
1829 var4 = par3;
1830 }
1831
1832 if (var4 < -par3)
1833 {
1834 var4 = -par3;
1835 }
1836
1837 return par1 + var4;
1838 }
1839
1840 /**
1841 * Checks if the entity's current position is a valid location to spawn this entity.
1842 */
1843 public boolean getCanSpawnHere()
1844 {
1845 return this.worldObj.checkIfAABBIsClear(this.boundingBox) && this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox);
1846 }
1847
1848 /**
1849 * sets the dead flag. Used when you fall off the bottom of the world.
1850 */
1851 protected void kill()
1852 {
1853 this.attackEntityFrom(DamageSource.outOfWorld, 4);
1854 }
1855
1856 @SideOnly(Side.CLIENT)
1857
1858 /**
1859 * Returns where in the swing animation the living entity is (from 0 to 1). Args: partialTickTime
1860 */
1861 public float getSwingProgress(float par1)
1862 {
1863 float var2 = this.swingProgress - this.prevSwingProgress;
1864
1865 if (var2 < 0.0F)
1866 {
1867 ++var2;
1868 }
1869
1870 return this.prevSwingProgress + var2 * par1;
1871 }
1872
1873 @SideOnly(Side.CLIENT)
1874
1875 /**
1876 * interpolated position vector
1877 */
1878 public Vec3 getPosition(float par1)
1879 {
1880 if (par1 == 1.0F)
1881 {
1882 return Vec3.getVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
1883 }
1884 else
1885 {
1886 double var2 = this.prevPosX + (this.posX - this.prevPosX) * (double)par1;
1887 double var4 = this.prevPosY + (this.posY - this.prevPosY) * (double)par1;
1888 double var6 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double)par1;
1889 return Vec3.getVec3Pool().getVecFromPool(var2, var4, var6);
1890 }
1891 }
1892
1893 /**
1894 * returns a (normalized) vector of where this entity is looking
1895 */
1896 public Vec3 getLookVec()
1897 {
1898 return this.getLook(1.0F);
1899 }
1900
1901 /**
1902 * interpolated look vector
1903 */
1904 public Vec3 getLook(float par1)
1905 {
1906 float var2;
1907 float var3;
1908 float var4;
1909 float var5;
1910
1911 if (par1 == 1.0F)
1912 {
1913 var2 = MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI);
1914 var3 = MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI);
1915 var4 = -MathHelper.cos(-this.rotationPitch * 0.017453292F);
1916 var5 = MathHelper.sin(-this.rotationPitch * 0.017453292F);
1917 return Vec3.getVec3Pool().getVecFromPool((double)(var3 * var4), (double)var5, (double)(var2 * var4));
1918 }
1919 else
1920 {
1921 var2 = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * par1;
1922 var3 = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * par1;
1923 var4 = MathHelper.cos(-var3 * 0.017453292F - (float)Math.PI);
1924 var5 = MathHelper.sin(-var3 * 0.017453292F - (float)Math.PI);
1925 float var6 = -MathHelper.cos(-var2 * 0.017453292F);
1926 float var7 = MathHelper.sin(-var2 * 0.017453292F);
1927 return Vec3.getVec3Pool().getVecFromPool((double)(var5 * var6), (double)var7, (double)(var4 * var6));
1928 }
1929 }
1930
1931 @SideOnly(Side.CLIENT)
1932
1933 /**
1934 * Returns render size modifier
1935 */
1936 public float getRenderSizeModifier()
1937 {
1938 return 1.0F;
1939 }
1940
1941 @SideOnly(Side.CLIENT)
1942
1943 /**
1944 * Performs a ray trace for the distance specified and using the partial tick time. Args: distance, partialTickTime
1945 */
1946 public MovingObjectPosition rayTrace(double par1, float par3)
1947 {
1948 Vec3 var4 = this.getPosition(par3);
1949 Vec3 var5 = this.getLook(par3);
1950 Vec3 var6 = var4.addVector(var5.xCoord * par1, var5.yCoord * par1, var5.zCoord * par1);
1951 return this.worldObj.rayTraceBlocks(var4, var6);
1952 }
1953
1954 /**
1955 * Will return how many at most can spawn in a chunk at once.
1956 */
1957 public int getMaxSpawnedInChunk()
1958 {
1959 return 4;
1960 }
1961
1962 @SideOnly(Side.CLIENT)
1963
1964 /**
1965 * Returns the item that this EntityLiving is holding, if any.
1966 */
1967 public ItemStack getHeldItem()
1968 {
1969 return null;
1970 }
1971
1972 @SideOnly(Side.CLIENT)
1973 public void handleHealthUpdate(byte par1)
1974 {
1975 if (par1 == 2)
1976 {
1977 this.legYaw = 1.5F;
1978 this.hurtResistantTime = this.maxHurtResistantTime;
1979 this.hurtTime = this.maxHurtTime = 10;
1980 this.attackedAtYaw = 0.0F;
1981 this.worldObj.playSoundAtEntity(this, this.getHurtSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
1982 this.attackEntityFrom(DamageSource.generic, 0);
1983 }
1984 else if (par1 == 3)
1985 {
1986 this.worldObj.playSoundAtEntity(this, this.getDeathSound(), this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
1987 this.health = 0;
1988 this.onDeath(DamageSource.generic);
1989 }
1990 else
1991 {
1992 super.handleHealthUpdate(par1);
1993 }
1994 }
1995
1996 /**
1997 * Returns whether player is sleeping or not
1998 */
1999 public boolean isPlayerSleeping()
2000 {
2001 return false;
2002 }
2003
2004 @SideOnly(Side.CLIENT)
2005
2006 /**
2007 * Gets the Icon Index of the item currently held
2008 */
2009 public int getItemIcon(ItemStack par1ItemStack, int par2)
2010 {
2011 return par1ItemStack.getIconIndex();
2012 }
2013
2014 protected void updatePotionEffects()
2015 {
2016 Iterator var1 = this.activePotionsMap.keySet().iterator();
2017
2018 while (var1.hasNext())
2019 {
2020 Integer var2 = (Integer)var1.next();
2021 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2022
2023 if (!var3.onUpdate(this) && !this.worldObj.isRemote)
2024 {
2025 var1.remove();
2026 this.onFinishedPotionEffect(var3);
2027 }
2028 }
2029
2030 int var9;
2031
2032 if (this.potionsNeedUpdate)
2033 {
2034 if (!this.worldObj.isRemote)
2035 {
2036 if (this.activePotionsMap.isEmpty())
2037 {
2038 this.dataWatcher.updateObject(8, Integer.valueOf(0));
2039 }
2040 else
2041 {
2042 var9 = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values());
2043 this.dataWatcher.updateObject(8, Integer.valueOf(var9));
2044 }
2045 }
2046
2047 this.potionsNeedUpdate = false;
2048 }
2049
2050 if (this.rand.nextBoolean())
2051 {
2052 var9 = this.dataWatcher.getWatchableObjectInt(8);
2053
2054 if (var9 > 0)
2055 {
2056 double var10 = (double)(var9 >> 16 & 255) / 255.0D;
2057 double var5 = (double)(var9 >> 8 & 255) / 255.0D;
2058 double var7 = (double)(var9 >> 0 & 255) / 255.0D;
2059 this.worldObj.spawnParticle("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, var10, var5, var7);
2060 }
2061 }
2062 }
2063
2064 public void clearActivePotions()
2065 {
2066 Iterator var1 = this.activePotionsMap.keySet().iterator();
2067
2068 while (var1.hasNext())
2069 {
2070 Integer var2 = (Integer)var1.next();
2071 PotionEffect var3 = (PotionEffect)this.activePotionsMap.get(var2);
2072
2073 if (!this.worldObj.isRemote)
2074 {
2075 var1.remove();
2076 this.onFinishedPotionEffect(var3);
2077 }
2078 }
2079 }
2080
2081 public Collection getActivePotionEffects()
2082 {
2083 return this.activePotionsMap.values();
2084 }
2085
2086 public boolean isPotionActive(Potion par1Potion)
2087 {
2088 return this.activePotionsMap.containsKey(Integer.valueOf(par1Potion.id));
2089 }
2090
2091 /**
2092 * returns the PotionEffect for the supplied Potion if it is active, null otherwise.
2093 */
2094 public PotionEffect getActivePotionEffect(Potion par1Potion)
2095 {
2096 return (PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1Potion.id));
2097 }
2098
2099 /**
2100 * adds a PotionEffect to the entity
2101 */
2102 public void addPotionEffect(PotionEffect par1PotionEffect)
2103 {
2104 if (this.isPotionApplicable(par1PotionEffect))
2105 {
2106 if (this.activePotionsMap.containsKey(Integer.valueOf(par1PotionEffect.getPotionID())))
2107 {
2108 ((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID()))).combine(par1PotionEffect);
2109 this.onChangedPotionEffect((PotionEffect)this.activePotionsMap.get(Integer.valueOf(par1PotionEffect.getPotionID())));
2110 }
2111 else
2112 {
2113 this.activePotionsMap.put(Integer.valueOf(par1PotionEffect.getPotionID()), par1PotionEffect);
2114 this.onNewPotionEffect(par1PotionEffect);
2115 }
2116 }
2117 }
2118
2119 public boolean isPotionApplicable(PotionEffect par1PotionEffect)
2120 {
2121 if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD)
2122 {
2123 int var2 = par1PotionEffect.getPotionID();
2124
2125 if (var2 == Potion.regeneration.id || var2 == Potion.poison.id)
2126 {
2127 return false;
2128 }
2129 }
2130
2131 return true;
2132 }
2133
2134 /**
2135 * Returns true if this entity is undead.
2136 */
2137 public boolean isEntityUndead()
2138 {
2139 return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD;
2140 }
2141
2142 /**
2143 * input is the potion id to remove from the current active potion effects
2144 */
2145 public void removePotionEffect(int par1)
2146 {
2147 this.activePotionsMap.remove(Integer.valueOf(par1));
2148 }
2149
2150 protected void onNewPotionEffect(PotionEffect par1PotionEffect)
2151 {
2152 this.potionsNeedUpdate = true;
2153 }
2154
2155 protected void onChangedPotionEffect(PotionEffect par1PotionEffect)
2156 {
2157 this.potionsNeedUpdate = true;
2158 }
2159
2160 protected void onFinishedPotionEffect(PotionEffect par1PotionEffect)
2161 {
2162 this.potionsNeedUpdate = true;
2163 }
2164
2165 /**
2166 * This method returns a value to be applied directly to entity speed, this factor is less than 1 when a slowdown
2167 * potion effect is applied, more than 1 when a haste potion effect is applied and 2 for fleeing entities.
2168 */
2169 protected float getSpeedModifier()
2170 {
2171 float var1 = 1.0F;
2172
2173 if (this.isPotionActive(Potion.moveSpeed))
2174 {
2175 var1 *= 1.0F + 0.2F * (float)(this.getActivePotionEffect(Potion.moveSpeed).getAmplifier() + 1);
2176 }
2177
2178 if (this.isPotionActive(Potion.moveSlowdown))
2179 {
2180 var1 *= 1.0F - 0.15F * (float)(this.getActivePotionEffect(Potion.moveSlowdown).getAmplifier() + 1);
2181 }
2182
2183 return var1;
2184 }
2185
2186 /**
2187 * Move the entity to the coordinates informed, but keep yaw/pitch values.
2188 */
2189 public void setPositionAndUpdate(double par1, double par3, double par5)
2190 {
2191 this.setLocationAndAngles(par1, par3, par5, this.rotationYaw, this.rotationPitch);
2192 }
2193
2194 /**
2195 * If Animal, checks if the age timer is negative
2196 */
2197 public boolean isChild()
2198 {
2199 return false;
2200 }
2201
2202 /**
2203 * Get this Entity's EnumCreatureAttribute
2204 */
2205 public EnumCreatureAttribute getCreatureAttribute()
2206 {
2207 return EnumCreatureAttribute.UNDEFINED;
2208 }
2209
2210 /**
2211 * Renders broken item particles using the given ItemStack
2212 */
2213 public void renderBrokenItemStack(ItemStack par1ItemStack)
2214 {
2215 this.worldObj.playSoundAtEntity(this, "random.break", 0.8F, 0.8F + this.worldObj.rand.nextFloat() * 0.4F);
2216
2217 for (int var2 = 0; var2 < 5; ++var2)
2218 {
2219 Vec3 var3 = Vec3.getVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
2220 var3.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2221 var3.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2222 Vec3 var4 = Vec3.getVec3Pool().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D);
2223 var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
2224 var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
2225 var4 = var4.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ);
2226 this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().shiftedIndex, var4.xCoord, var4.yCoord, var4.zCoord, var3.xCoord, var3.yCoord + 0.05D, var3.zCoord);
2227 }
2228 }
2229
2230 /***
2231 * Removes all potion effects that have curativeItem as a curative item for its effect
2232 * @param curativeItem The itemstack we are using to cure potion effects
2233 */
2234 public void curePotionEffects(ItemStack curativeItem)
2235 {
2236 Iterator<Integer> potionKey = activePotionsMap.keySet().iterator();
2237
2238 if (worldObj.isRemote)
2239 {
2240 return;
2241 }
2242
2243 while (potionKey.hasNext())
2244 {
2245 Integer key = potionKey.next();
2246 PotionEffect effect = (PotionEffect)activePotionsMap.get(key);
2247
2248 if (effect.isCurativeItem(curativeItem))
2249 {
2250 potionKey.remove();
2251 onFinishedPotionEffect(effect);
2252 }
2253 }
2254 }
2255 }