001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.FMLCommonHandler;
004 import cpw.mods.fml.common.Side;
005 import cpw.mods.fml.common.asm.SideOnly;
006 import cpw.mods.fml.common.network.FMLNetworkHandler;
007
008 import java.util.Iterator;
009 import java.util.List;
010
011 import net.minecraftforge.common.ForgeHooks;
012 import net.minecraftforge.common.ISpecialArmor.ArmorProperties;
013 import net.minecraftforge.common.MinecraftForge;
014 import net.minecraftforge.event.ForgeEventFactory;
015 import net.minecraftforge.event.entity.living.LivingHurtEvent;
016 import net.minecraftforge.event.entity.player.AttackEntityEvent;
017 import net.minecraftforge.event.entity.player.EntityInteractEvent;
018 import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
019 import net.minecraftforge.event.entity.player.PlayerDropsEvent;
020 import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
021
022 public abstract class EntityPlayer extends EntityLiving implements ICommandSender
023 {
024 /** Inventory of the player */
025 public InventoryPlayer inventory = new InventoryPlayer(this);
026 private InventoryEnderChest theInventoryEnderChest = new InventoryEnderChest();
027
028 /** the crafting inventory in you get when opening your inventory */
029 public Container inventorySlots;
030
031 /** the crafting inventory you are currently using */
032 public Container craftingInventory;
033
034 /** The player's food stats. (See class FoodStats) */
035 protected FoodStats foodStats = new FoodStats();
036
037 /**
038 * Used to tell if the player pressed jump twice. If this is at 0 and it's pressed (And they are allowed to fly, as
039 * defined in the player's movementInput) it sets this to 7. If it's pressed and it's greater than 0 enable fly.
040 */
041 protected int flyToggleTimer = 0;
042 public byte field_71098_bD = 0;
043 public int score = 0;
044 public float prevCameraYaw;
045 public float cameraYaw;
046 public String username;
047 @SideOnly(Side.CLIENT)
048 public String playerCloakUrl;
049
050 /**
051 * Used by EntityPlayer to prevent too many xp orbs from getting absorbed at once.
052 */
053 public int xpCooldown = 0;
054 public double field_71091_bM;
055 public double field_71096_bN;
056 public double field_71097_bO;
057 public double field_71094_bP;
058 public double field_71095_bQ;
059 public double field_71085_bR;
060
061 /** Boolean value indicating weather a player is sleeping or not */
062 protected boolean sleeping;
063
064 /**
065 * The chunk coordinates of the bed the player is in (null if player isn't in a bed).
066 */
067 public ChunkCoordinates playerLocation;
068 private int sleepTimer;
069 public float field_71079_bU;
070 @SideOnly(Side.CLIENT)
071 public float field_71082_cx;
072 public float field_71089_bV;
073
074 /**
075 * Holds the last coordinate to spawn based on last bed that the player sleep.
076 */
077 private ChunkCoordinates spawnChunk;
078 private boolean field_82248_d;
079
080 /** Holds the coordinate of the player when enter a minecraft to ride. */
081 private ChunkCoordinates startMinecartRidingCoordinate;
082
083 /** The player's capabilities. (See class PlayerCapabilities) */
084 public PlayerCapabilities capabilities = new PlayerCapabilities();
085
086 /** The current experience level the player is on. */
087 public int experienceLevel;
088
089 /**
090 * The total amount of experience the player has. This also includes the amount of experience within their
091 * Experience Bar.
092 */
093 public int experienceTotal;
094
095 /**
096 * The current amount of experience the player has within their Experience Bar.
097 */
098 public float experience;
099
100 /**
101 * This is the item that is in use when the player is holding down the useItemButton (e.g., bow, food, sword)
102 */
103 private ItemStack itemInUse;
104
105 /**
106 * This field starts off equal to getMaxItemUseDuration and is decremented on each tick
107 */
108 private int itemInUseCount;
109 protected float speedOnGround = 0.1F;
110 protected float speedInAir = 0.02F;
111 private int field_82249_h = 0;
112
113 /**
114 * An instance of a fishing rod's hook. If this isn't null, the icon image of the fishing rod is slightly different
115 */
116 public EntityFishHook fishEntity = null;
117
118 public EntityPlayer(World par1World)
119 {
120 super(par1World);
121 this.inventorySlots = new ContainerPlayer(this.inventory, !par1World.isRemote, this);
122 this.craftingInventory = this.inventorySlots;
123 this.yOffset = 1.62F;
124 ChunkCoordinates var2 = par1World.getSpawnPoint();
125 this.setLocationAndAngles((double)var2.posX + 0.5D, (double)(var2.posY + 1), (double)var2.posZ + 0.5D, 0.0F, 0.0F);
126 this.entityType = "humanoid";
127 this.field_70741_aB = 180.0F;
128 this.fireResistance = 20;
129 this.texture = "/mob/char.png";
130 }
131
132 public int getMaxHealth()
133 {
134 return 20;
135 }
136
137 protected void entityInit()
138 {
139 super.entityInit();
140 this.dataWatcher.addObject(16, Byte.valueOf((byte)0));
141 this.dataWatcher.addObject(17, Byte.valueOf((byte)0));
142 }
143
144 @SideOnly(Side.CLIENT)
145
146 /**
147 * returns the ItemStack containing the itemInUse
148 */
149 public ItemStack getItemInUse()
150 {
151 return this.itemInUse;
152 }
153
154 @SideOnly(Side.CLIENT)
155
156 /**
157 * Returns the item in use count
158 */
159 public int getItemInUseCount()
160 {
161 return this.itemInUseCount;
162 }
163
164 /**
165 * Checks if the entity is currently using an item (e.g., bow, food, sword) by holding down the useItemButton
166 */
167 public boolean isUsingItem()
168 {
169 return this.itemInUse != null;
170 }
171
172 @SideOnly(Side.CLIENT)
173
174 /**
175 * gets the duration for how long the current itemInUse has been in use
176 */
177 public int getItemInUseDuration()
178 {
179 return this.isUsingItem() ? this.itemInUse.getMaxItemUseDuration() - this.itemInUseCount : 0;
180 }
181
182 public void stopUsingItem()
183 {
184 if (this.itemInUse != null)
185 {
186 this.itemInUse.onPlayerStoppedUsing(this.worldObj, this, this.itemInUseCount);
187 }
188
189 this.clearItemInUse();
190 }
191
192 public void clearItemInUse()
193 {
194 this.itemInUse = null;
195 this.itemInUseCount = 0;
196
197 if (!this.worldObj.isRemote)
198 {
199 this.setEating(false);
200 }
201 }
202
203 public boolean isBlocking()
204 {
205 return this.isUsingItem() && Item.itemsList[this.itemInUse.itemID].getItemUseAction(this.itemInUse) == EnumAction.block;
206 }
207
208 /**
209 * Called to update the entity's position/logic.
210 */
211 public void onUpdate()
212 {
213 FMLCommonHandler.instance().onPlayerPreTick(this);
214 if (this.itemInUse != null)
215 {
216 ItemStack var1 = this.inventory.getCurrentItem();
217
218 if (var1 == this.itemInUse)
219 {
220 itemInUse.getItem().onUsingItemTick(itemInUse, this, itemInUseCount);
221 if (this.itemInUseCount <= 25 && this.itemInUseCount % 4 == 0)
222 {
223 this.updateItemUse(var1, 5);
224 }
225
226 if (--this.itemInUseCount == 0 && !this.worldObj.isRemote)
227 {
228 this.onItemUseFinish();
229 }
230 }
231 else
232 {
233 this.clearItemInUse();
234 }
235 }
236
237 if (this.xpCooldown > 0)
238 {
239 --this.xpCooldown;
240 }
241
242 if (this.isPlayerSleeping())
243 {
244 ++this.sleepTimer;
245
246 if (this.sleepTimer > 100)
247 {
248 this.sleepTimer = 100;
249 }
250
251 if (!this.worldObj.isRemote)
252 {
253 if (!this.isInBed())
254 {
255 this.wakeUpPlayer(true, true, false);
256 }
257 else if (this.worldObj.isDaytime())
258 {
259 this.wakeUpPlayer(false, true, true);
260 }
261 }
262 }
263 else if (this.sleepTimer > 0)
264 {
265 ++this.sleepTimer;
266
267 if (this.sleepTimer >= 110)
268 {
269 this.sleepTimer = 0;
270 }
271 }
272
273 super.onUpdate();
274
275 if (!this.worldObj.isRemote && this.craftingInventory != null && !this.craftingInventory.canInteractWith(this))
276 {
277 this.closeScreen();
278 this.craftingInventory = this.inventorySlots;
279 }
280
281 if (this.isBurning() && this.capabilities.disableDamage)
282 {
283 this.extinguish();
284 }
285
286 this.field_71091_bM = this.field_71094_bP;
287 this.field_71096_bN = this.field_71095_bQ;
288 this.field_71097_bO = this.field_71085_bR;
289 double var9 = this.posX - this.field_71094_bP;
290 double var3 = this.posY - this.field_71095_bQ;
291 double var5 = this.posZ - this.field_71085_bR;
292 double var7 = 10.0D;
293
294 if (var9 > var7)
295 {
296 this.field_71091_bM = this.field_71094_bP = this.posX;
297 }
298
299 if (var5 > var7)
300 {
301 this.field_71097_bO = this.field_71085_bR = this.posZ;
302 }
303
304 if (var3 > var7)
305 {
306 this.field_71096_bN = this.field_71095_bQ = this.posY;
307 }
308
309 if (var9 < -var7)
310 {
311 this.field_71091_bM = this.field_71094_bP = this.posX;
312 }
313
314 if (var5 < -var7)
315 {
316 this.field_71097_bO = this.field_71085_bR = this.posZ;
317 }
318
319 if (var3 < -var7)
320 {
321 this.field_71096_bN = this.field_71095_bQ = this.posY;
322 }
323
324 this.field_71094_bP += var9 * 0.25D;
325 this.field_71085_bR += var5 * 0.25D;
326 this.field_71095_bQ += var3 * 0.25D;
327 this.addStat(StatList.minutesPlayedStat, 1);
328
329 if (this.ridingEntity == null)
330 {
331 this.startMinecartRidingCoordinate = null;
332 }
333
334 if (!this.worldObj.isRemote)
335 {
336 this.foodStats.onUpdate(this);
337 }
338 FMLCommonHandler.instance().onPlayerPostTick(this);
339 }
340
341 public int func_82145_z()
342 {
343 return this.capabilities.disableDamage ? 0 : 80;
344 }
345
346 public int func_82147_ab()
347 {
348 return 10;
349 }
350
351 /**
352 * Plays sounds and makes particles for item in use state
353 */
354 protected void updateItemUse(ItemStack par1ItemStack, int par2)
355 {
356 if (par1ItemStack.getItemUseAction() == EnumAction.drink)
357 {
358 this.worldObj.playSoundAtEntity(this, "random.drink", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
359 }
360
361 if (par1ItemStack.getItemUseAction() == EnumAction.eat)
362 {
363 for (int var3 = 0; var3 < par2; ++var3)
364 {
365 Vec3 var4 = this.worldObj.func_82732_R().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
366 var4.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
367 var4.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
368 Vec3 var5 = this.worldObj.func_82732_R().getVecFromPool(((double)this.rand.nextFloat() - 0.5D) * 0.3D, (double)(-this.rand.nextFloat()) * 0.6D - 0.3D, 0.6D);
369 var5.rotateAroundX(-this.rotationPitch * (float)Math.PI / 180.0F);
370 var5.rotateAroundY(-this.rotationYaw * (float)Math.PI / 180.0F);
371 var5 = var5.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ);
372 this.worldObj.spawnParticle("iconcrack_" + par1ItemStack.getItem().shiftedIndex, var5.xCoord, var5.yCoord, var5.zCoord, var4.xCoord, var4.yCoord + 0.05D, var4.zCoord);
373 }
374
375 this.worldObj.playSoundAtEntity(this, "random.eat", 0.5F + 0.5F * (float)this.rand.nextInt(2), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F);
376 }
377 }
378
379 /**
380 * Used for when item use count runs out, ie: eating completed
381 */
382 protected void onItemUseFinish()
383 {
384 if (this.itemInUse != null)
385 {
386 this.updateItemUse(this.itemInUse, 16);
387 int var1 = this.itemInUse.stackSize;
388 ItemStack var2 = this.itemInUse.onFoodEaten(this.worldObj, this);
389
390 if (var2 != this.itemInUse || var2 != null && var2.stackSize != var1)
391 {
392 this.inventory.mainInventory[this.inventory.currentItem] = var2;
393
394 if (var2.stackSize == 0)
395 {
396 this.inventory.mainInventory[this.inventory.currentItem] = null;
397 }
398 }
399
400 this.clearItemInUse();
401 }
402 }
403
404 @SideOnly(Side.CLIENT)
405 public void handleHealthUpdate(byte par1)
406 {
407 if (par1 == 9)
408 {
409 this.onItemUseFinish();
410 }
411 else
412 {
413 super.handleHealthUpdate(par1);
414 }
415 }
416
417 /**
418 * Dead and sleeping entities cannot move
419 */
420 protected boolean isMovementBlocked()
421 {
422 return this.getHealth() <= 0 || this.isPlayerSleeping();
423 }
424
425 /**
426 * sets current screen to null (used on escape buttons of GUIs)
427 */
428 public void closeScreen()
429 {
430 this.craftingInventory = this.inventorySlots;
431 }
432
433 /**
434 * Handles updating while being ridden by an entity
435 */
436 public void updateRidden()
437 {
438 double var1 = this.posX;
439 double var3 = this.posY;
440 double var5 = this.posZ;
441 float var7 = this.rotationYaw;
442 float var8 = this.rotationPitch;
443 super.updateRidden();
444 this.prevCameraYaw = this.cameraYaw;
445 this.cameraYaw = 0.0F;
446 this.addMountedMovementStat(this.posX - var1, this.posY - var3, this.posZ - var5);
447
448 if (this.ridingEntity instanceof EntityPig)
449 {
450 this.rotationPitch = var8;
451 this.rotationYaw = var7;
452 this.renderYawOffset = ((EntityPig)this.ridingEntity).renderYawOffset;
453 }
454 }
455
456 @SideOnly(Side.CLIENT)
457
458 /**
459 * Keeps moving the entity up so it isn't colliding with blocks and other requirements for this entity to be spawned
460 * (only actually used on players though its also on Entity)
461 */
462 public void preparePlayerToSpawn()
463 {
464 this.yOffset = 1.62F;
465 this.setSize(0.6F, 1.8F);
466 super.preparePlayerToSpawn();
467 this.setEntityHealth(this.getMaxHealth());
468 this.deathTime = 0;
469 }
470
471 protected void updateEntityActionState()
472 {
473 this.func_82168_bl();
474 }
475
476 /**
477 * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
478 * use this to react to sunlight and start to burn.
479 */
480 public void onLivingUpdate()
481 {
482 if (this.flyToggleTimer > 0)
483 {
484 --this.flyToggleTimer;
485 }
486
487 if (this.worldObj.difficultySetting == 0 && this.getHealth() < this.getMaxHealth() && this.ticksExisted % 20 * 12 == 0)
488 {
489 this.heal(1);
490 }
491
492 this.inventory.decrementAnimations();
493 this.prevCameraYaw = this.cameraYaw;
494 super.onLivingUpdate();
495 this.landMovementFactor = this.capabilities.getWalkSpeed();
496 this.jumpMovementFactor = this.speedInAir;
497
498 if (this.isSprinting())
499 {
500 this.landMovementFactor = (float)((double)this.landMovementFactor + (double)this.capabilities.getWalkSpeed() * 0.3D);
501 this.jumpMovementFactor = (float)((double)this.jumpMovementFactor + (double)this.speedInAir * 0.3D);
502 }
503
504 float var1 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
505 float var2 = (float)Math.atan(-this.motionY * 0.20000000298023224D) * 15.0F;
506
507 if (var1 > 0.1F)
508 {
509 var1 = 0.1F;
510 }
511
512 if (!this.onGround || this.getHealth() <= 0)
513 {
514 var1 = 0.0F;
515 }
516
517 if (this.onGround || this.getHealth() <= 0)
518 {
519 var2 = 0.0F;
520 }
521
522 this.cameraYaw += (var1 - this.cameraYaw) * 0.4F;
523 this.cameraPitch += (var2 - this.cameraPitch) * 0.8F;
524
525 if (this.getHealth() > 0)
526 {
527 List var3 = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.expand(1.0D, 0.0D, 1.0D));
528
529 if (var3 != null)
530 {
531 Iterator var4 = var3.iterator();
532
533 while (var4.hasNext())
534 {
535 Entity var5 = (Entity)var4.next();
536
537 if (!var5.isDead)
538 {
539 this.collideWithPlayer(var5);
540 }
541 }
542 }
543 }
544 }
545
546 private void collideWithPlayer(Entity par1Entity)
547 {
548 par1Entity.onCollideWithPlayer(this);
549 }
550
551 @SideOnly(Side.CLIENT)
552 public int getScore()
553 {
554 return this.score;
555 }
556
557 /**
558 * Called when the mob's health reaches 0.
559 */
560 public void onDeath(DamageSource par1DamageSource)
561 {
562 super.onDeath(par1DamageSource);
563 this.setSize(0.2F, 0.2F);
564 this.setPosition(this.posX, this.posY, this.posZ);
565 this.motionY = 0.10000000149011612D;
566
567 captureDrops = true;
568 capturedDrops.clear();
569
570 if (this.username.equals("Notch"))
571 {
572 this.dropPlayerItemWithRandomChoice(new ItemStack(Item.appleRed, 1), true);
573 }
574
575 if (!this.worldObj.func_82736_K().func_82766_b("keepInventory"))
576 {
577 this.inventory.dropAllItems();
578 }
579
580 captureDrops = false;
581
582 if (!worldObj.isRemote)
583 {
584 PlayerDropsEvent event = new PlayerDropsEvent(this, par1DamageSource, capturedDrops, recentlyHit > 0);
585 if (!MinecraftForge.EVENT_BUS.post(event))
586 {
587 for (EntityItem item : capturedDrops)
588 {
589 joinEntityItemWithWorld(item);
590 }
591 }
592 }
593
594 if (par1DamageSource != null)
595 {
596 this.motionX = (double)(-MathHelper.cos((this.attackedAtYaw + this.rotationYaw) * (float)Math.PI / 180.0F) * 0.1F);
597 this.motionZ = (double)(-MathHelper.sin((this.attackedAtYaw + this.rotationYaw) * (float)Math.PI / 180.0F) * 0.1F);
598 }
599 else
600 {
601 this.motionX = this.motionZ = 0.0D;
602 }
603
604 this.yOffset = 0.1F;
605 this.addStat(StatList.deathsStat, 1);
606 }
607
608 /**
609 * Adds a value to the player score. Currently not actually used and the entity passed in does nothing. Args:
610 * entity, scoreToAdd
611 */
612 public void addToPlayerScore(Entity par1Entity, int par2)
613 {
614 this.score += par2;
615
616 if (par1Entity instanceof EntityPlayer)
617 {
618 this.addStat(StatList.playerKillsStat, 1);
619 }
620 else
621 {
622 this.addStat(StatList.mobKillsStat, 1);
623 }
624 }
625
626 /**
627 * Called when player presses the drop item key
628 */
629 public EntityItem dropOneItem()
630 {
631 ItemStack stack = inventory.getCurrentItem();
632 if (stack == null)
633 {
634 return null;
635 }
636 if (stack.getItem().onDroppedByPlayer(stack, this))
637 {
638 return ForgeHooks.onPlayerTossEvent(this, inventory.decrStackSize(inventory.currentItem, 1));
639 }
640 return null;
641 }
642
643 /**
644 * Args: itemstack - called when player drops an item stack that's not in his inventory (like items still placed in
645 * a workbench while the workbench'es GUI gets closed)
646 */
647 public EntityItem dropPlayerItem(ItemStack par1ItemStack)
648 {
649 return ForgeHooks.onPlayerTossEvent(this, par1ItemStack);
650 }
651
652 /**
653 * Args: itemstack, flag
654 */
655 public EntityItem dropPlayerItemWithRandomChoice(ItemStack par1ItemStack, boolean par2)
656 {
657 if (par1ItemStack == null)
658 {
659 return null;
660 }
661 else
662 {
663 EntityItem var3 = new EntityItem(this.worldObj, this.posX, this.posY - 0.30000001192092896D + (double)this.getEyeHeight(), this.posZ, par1ItemStack);
664 var3.delayBeforeCanPickup = 40;
665 float var4 = 0.1F;
666 float var5;
667
668 if (par2)
669 {
670 var5 = this.rand.nextFloat() * 0.5F;
671 float var6 = this.rand.nextFloat() * (float)Math.PI * 2.0F;
672 var3.motionX = (double)(-MathHelper.sin(var6) * var5);
673 var3.motionZ = (double)(MathHelper.cos(var6) * var5);
674 var3.motionY = 0.20000000298023224D;
675 }
676 else
677 {
678 var4 = 0.3F;
679 var3.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * var4);
680 var3.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * var4);
681 var3.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI) * var4 + 0.1F);
682 var4 = 0.02F;
683 var5 = this.rand.nextFloat() * (float)Math.PI * 2.0F;
684 var4 *= this.rand.nextFloat();
685 var3.motionX += Math.cos((double)var5) * (double)var4;
686 var3.motionY += (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.1F);
687 var3.motionZ += Math.sin((double)var5) * (double)var4;
688 }
689
690 this.joinEntityItemWithWorld(var3);
691 this.addStat(StatList.dropStat, 1);
692 return var3;
693 }
694 }
695
696 /**
697 * Joins the passed in entity item with the world. Args: entityItem
698 */
699 public void joinEntityItemWithWorld(EntityItem par1EntityItem)
700 {
701 if (captureDrops)
702 {
703 capturedDrops.add(par1EntityItem);
704 }
705 else
706 {
707 this.worldObj.spawnEntityInWorld(par1EntityItem);
708 }
709 }
710
711 /**
712 * Returns how strong the player is against the specified block at this moment
713 * Deprecated in favor of the more sensitive version
714 */
715 @Deprecated
716 public float getCurrentPlayerStrVsBlock(Block par1Block)
717 {
718 return getCurrentPlayerStrVsBlock(par1Block, 0);
719 }
720
721 public float getCurrentPlayerStrVsBlock(Block par1Block, int meta)
722 {
723 ItemStack stack = inventory.getCurrentItem();
724 float var2 = (stack == null ? 1.0F : stack.getItem().getStrVsBlock(stack, par1Block, meta));
725 int var3 = EnchantmentHelper.getEfficiencyModifier(this);
726
727 if (var3 > 0 && ForgeHooks.canHarvestBlock(par1Block, this, meta))
728 {
729 var2 += (float)(var3 * var3 + 1);
730 }
731
732 if (this.isPotionActive(Potion.digSpeed))
733 {
734 var2 *= 1.0F + (float)(this.getActivePotionEffect(Potion.digSpeed).getAmplifier() + 1) * 0.2F;
735 }
736
737 if (this.isPotionActive(Potion.digSlowdown))
738 {
739 var2 *= 1.0F - (float)(this.getActivePotionEffect(Potion.digSlowdown).getAmplifier() + 1) * 0.2F;
740 }
741
742 if (this.isInsideOfMaterial(Material.water) && !EnchantmentHelper.getAquaAffinityModifier(this))
743 {
744 var2 /= 5.0F;
745 }
746
747 if (!this.onGround)
748 {
749 var2 /= 5.0F;
750 }
751
752 var2 = ForgeEventFactory.getBreakSpeed(this, par1Block, meta, var2);
753 return (var2 < 0 ? 0 : var2);
754 }
755
756 /**
757 * Checks if the player has the ability to harvest a block (checks current inventory item for a tool if necessary)
758 */
759 public boolean canHarvestBlock(Block par1Block)
760 {
761 return ForgeEventFactory.doPlayerHarvestCheck(this, par1Block, inventory.canHarvestBlock(par1Block));
762 }
763
764 /**
765 * (abstract) Protected helper method to read subclass entity data from NBT.
766 */
767 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
768 {
769 super.readEntityFromNBT(par1NBTTagCompound);
770 NBTTagList var2 = par1NBTTagCompound.getTagList("Inventory");
771 this.inventory.readFromNBT(var2);
772 this.sleeping = par1NBTTagCompound.getBoolean("Sleeping");
773 this.sleepTimer = par1NBTTagCompound.getShort("SleepTimer");
774 this.experience = par1NBTTagCompound.getFloat("XpP");
775 this.experienceLevel = par1NBTTagCompound.getInteger("XpLevel");
776 this.experienceTotal = par1NBTTagCompound.getInteger("XpTotal");
777
778 if (this.sleeping)
779 {
780 this.playerLocation = new ChunkCoordinates(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
781 this.wakeUpPlayer(true, true, false);
782 }
783
784 if (par1NBTTagCompound.hasKey("SpawnX") && par1NBTTagCompound.hasKey("SpawnY") && par1NBTTagCompound.hasKey("SpawnZ"))
785 {
786 this.spawnChunk = new ChunkCoordinates(par1NBTTagCompound.getInteger("SpawnX"), par1NBTTagCompound.getInteger("SpawnY"), par1NBTTagCompound.getInteger("SpawnZ"));
787 this.field_82248_d = par1NBTTagCompound.getBoolean("SpawnForced");
788 }
789
790 this.foodStats.readNBT(par1NBTTagCompound);
791 this.capabilities.readCapabilitiesFromNBT(par1NBTTagCompound);
792
793 if (par1NBTTagCompound.hasKey("EnderItems"))
794 {
795 NBTTagList var3 = par1NBTTagCompound.getTagList("EnderItems");
796 this.theInventoryEnderChest.loadInventoryFromNBT(var3);
797 }
798 }
799
800 /**
801 * (abstract) Protected helper method to write subclass entity data to NBT.
802 */
803 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
804 {
805 super.writeEntityToNBT(par1NBTTagCompound);
806 par1NBTTagCompound.setTag("Inventory", this.inventory.writeToNBT(new NBTTagList()));
807 par1NBTTagCompound.setBoolean("Sleeping", this.sleeping);
808 par1NBTTagCompound.setShort("SleepTimer", (short)this.sleepTimer);
809 par1NBTTagCompound.setFloat("XpP", this.experience);
810 par1NBTTagCompound.setInteger("XpLevel", this.experienceLevel);
811 par1NBTTagCompound.setInteger("XpTotal", this.experienceTotal);
812
813 if (this.spawnChunk != null)
814 {
815 par1NBTTagCompound.setInteger("SpawnX", this.spawnChunk.posX);
816 par1NBTTagCompound.setInteger("SpawnY", this.spawnChunk.posY);
817 par1NBTTagCompound.setInteger("SpawnZ", this.spawnChunk.posZ);
818 par1NBTTagCompound.setBoolean("SpawnForced", this.field_82248_d);
819 }
820
821 this.foodStats.writeNBT(par1NBTTagCompound);
822 this.capabilities.writeCapabilitiesToNBT(par1NBTTagCompound);
823 par1NBTTagCompound.setTag("EnderItems", this.theInventoryEnderChest.saveInventoryToNBT());
824 }
825
826 /**
827 * Displays the GUI for interacting with a chest inventory. Args: chestInventory
828 */
829 public void displayGUIChest(IInventory par1IInventory) {}
830
831 public void displayGUIEnchantment(int par1, int par2, int par3) {}
832
833 public void func_82244_d(int par1, int par2, int par3) {}
834
835 /**
836 * Displays the crafting GUI for a workbench.
837 */
838 public void displayGUIWorkbench(int par1, int par2, int par3) {}
839
840 public float getEyeHeight()
841 {
842 return 0.12F;
843 }
844
845 /**
846 * sets the players height back to normal after doing things like sleeping and dieing
847 */
848 protected void resetHeight()
849 {
850 this.yOffset = 1.62F;
851 }
852
853 /**
854 * Called when the entity is attacked.
855 */
856 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
857 {
858 if (this.capabilities.disableDamage && !par1DamageSource.canHarmInCreative())
859 {
860 return false;
861 }
862 else
863 {
864 this.entityAge = 0;
865
866 if (this.getHealth() <= 0)
867 {
868 return false;
869 }
870 else
871 {
872 if (this.isPlayerSleeping() && !this.worldObj.isRemote)
873 {
874 this.wakeUpPlayer(true, true, false);
875 }
876
877 if (par1DamageSource.func_76350_n())
878 {
879 if (this.worldObj.difficultySetting == 0)
880 {
881 par2 = 0;
882 }
883
884 if (this.worldObj.difficultySetting == 1)
885 {
886 par2 = par2 / 2 + 1;
887 }
888
889 if (this.worldObj.difficultySetting == 3)
890 {
891 par2 = par2 * 3 / 2;
892 }
893 }
894
895 if (par2 == 0)
896 {
897 return false;
898 }
899 else
900 {
901 Entity var3 = par1DamageSource.getEntity();
902
903 if (var3 instanceof EntityArrow && ((EntityArrow)var3).shootingEntity != null)
904 {
905 var3 = ((EntityArrow)var3).shootingEntity;
906 }
907
908 if (var3 instanceof EntityLiving)
909 {
910 this.alertWolves((EntityLiving)var3, false);
911 }
912
913 this.addStat(StatList.damageTakenStat, par2);
914 return super.attackEntityFrom(par1DamageSource, par2);
915 }
916 }
917 }
918 }
919
920 /**
921 * Reduces damage, depending on potions
922 */
923 protected int applyPotionDamageCalculations(DamageSource par1DamageSource, int par2)
924 {
925 int var3 = super.applyPotionDamageCalculations(par1DamageSource, par2);
926
927 if (var3 <= 0)
928 {
929 return 0;
930 }
931 else
932 {
933 int var4 = EnchantmentHelper.getEnchantmentModifierDamage(this.inventory.armorInventory, par1DamageSource);
934
935 if (var4 > 20)
936 {
937 var4 = 20;
938 }
939
940 if (var4 > 0 && var4 <= 20)
941 {
942 int var5 = 25 - var4;
943 int var6 = var3 * var5 + this.carryoverDamage;
944 var3 = var6 / 25;
945 this.carryoverDamage = var6 % 25;
946 }
947
948 return var3;
949 }
950 }
951
952 /**
953 * returns if pvp is enabled or not
954 */
955 protected boolean isPVPEnabled()
956 {
957 return false;
958 }
959
960 /**
961 * Called when the player attack or gets attacked, it's alert all wolves in the area that are owned by the player to
962 * join the attack or defend the player.
963 */
964 protected void alertWolves(EntityLiving par1EntityLiving, boolean par2)
965 {
966 if (!(par1EntityLiving instanceof EntityCreeper) && !(par1EntityLiving instanceof EntityGhast))
967 {
968 if (par1EntityLiving instanceof EntityWolf)
969 {
970 EntityWolf var3 = (EntityWolf)par1EntityLiving;
971
972 if (var3.isTamed() && this.username.equals(var3.getOwnerName()))
973 {
974 return;
975 }
976 }
977
978 if (!(par1EntityLiving instanceof EntityPlayer) || this.isPVPEnabled())
979 {
980 List var6 = this.worldObj.getEntitiesWithinAABB(EntityWolf.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool(this.posX, this.posY, this.posZ, this.posX + 1.0D, this.posY + 1.0D, this.posZ + 1.0D).expand(16.0D, 4.0D, 16.0D));
981 Iterator var4 = var6.iterator();
982
983 while (var4.hasNext())
984 {
985 EntityWolf var5 = (EntityWolf)var4.next();
986
987 if (var5.isTamed() && var5.getEntityToAttack() == null && this.username.equals(var5.getOwnerName()) && (!par2 || !var5.isSitting()))
988 {
989 var5.setSitting(false);
990 var5.setTarget(par1EntityLiving);
991 }
992 }
993 }
994 }
995 }
996
997 protected void damageArmor(int par1)
998 {
999 this.inventory.damageArmor(par1);
1000 }
1001
1002 /**
1003 * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
1004 */
1005 public int getTotalArmorValue()
1006 {
1007 return this.inventory.getTotalArmorValue();
1008 }
1009
1010 public float func_82243_bO()
1011 {
1012 int var1 = 0;
1013 ItemStack[] var2 = this.inventory.armorInventory;
1014 int var3 = var2.length;
1015
1016 for (int var4 = 0; var4 < var3; ++var4)
1017 {
1018 ItemStack var5 = var2[var4];
1019
1020 if (var5 != null)
1021 {
1022 ++var1;
1023 }
1024 }
1025
1026 return (float)var1 / (float)this.inventory.armorInventory.length;
1027 }
1028
1029 /**
1030 * Deals damage to the entity. If its a EntityPlayer then will take damage from the armor first and then health
1031 * second with the reduced value. Args: damageAmount
1032 */
1033 protected void damageEntity(DamageSource par1DamageSource, int par2)
1034 {
1035 LivingHurtEvent event = new LivingHurtEvent(this, par1DamageSource, par2);
1036 if (MinecraftForge.EVENT_BUS.post(event) || event.ammount == 0)
1037 {
1038 return;
1039 }
1040 par2 = event.ammount;
1041
1042 if (!par1DamageSource.isUnblockable() && this.isBlocking())
1043 {
1044 par2 = 1 + par2 >> 1;
1045 }
1046
1047 par2 = ArmorProperties.ApplyArmor(this, inventory.armorInventory, par1DamageSource, par2);
1048 if (par2 <= 0)
1049 {
1050 return;
1051 }
1052 par2 = this.applyPotionDamageCalculations(par1DamageSource, par2);
1053 this.addExhaustion(par1DamageSource.getHungerDamage());
1054 this.health -= par2;
1055 }
1056
1057 /**
1058 * Displays the furnace GUI for the passed in furnace entity. Args: tileEntityFurnace
1059 */
1060 public void displayGUIFurnace(TileEntityFurnace par1TileEntityFurnace) {}
1061
1062 /**
1063 * Displays the dipsenser GUI for the passed in dispenser entity. Args: TileEntityDispenser
1064 */
1065 public void displayGUIDispenser(TileEntityDispenser par1TileEntityDispenser) {}
1066
1067 /**
1068 * Displays the GUI for editing a sign. Args: tileEntitySign
1069 */
1070 public void displayGUIEditSign(TileEntity par1TileEntity) {}
1071
1072 /**
1073 * Displays the GUI for interacting with a brewing stand.
1074 */
1075 public void displayGUIBrewingStand(TileEntityBrewingStand par1TileEntityBrewingStand) {}
1076
1077 public void func_82240_a(TileEntityBeacon par1TileEntityBeacon) {}
1078
1079 public void displayGUIMerchant(IMerchant par1IMerchant) {}
1080
1081 /**
1082 * Displays the GUI for interacting with a book.
1083 */
1084 public void displayGUIBook(ItemStack par1ItemStack) {}
1085
1086 public boolean interactWith(Entity par1Entity)
1087 {
1088 if (MinecraftForge.EVENT_BUS.post(new EntityInteractEvent(this, par1Entity)))
1089 {
1090 return false;
1091 }
1092 if (par1Entity.interact(this))
1093 {
1094 return true;
1095 }
1096 else
1097 {
1098 ItemStack var2 = this.getCurrentEquippedItem();
1099
1100 if (var2 != null && par1Entity instanceof EntityLiving)
1101 {
1102 if (this.capabilities.isCreativeMode)
1103 {
1104 var2 = var2.copy();
1105 }
1106
1107 if (var2.interactWith((EntityLiving)par1Entity))
1108 {
1109 if (var2.stackSize <= 0 && !this.capabilities.isCreativeMode)
1110 {
1111 this.destroyCurrentEquippedItem();
1112 }
1113
1114 return true;
1115 }
1116 }
1117
1118 return false;
1119 }
1120 }
1121
1122 /**
1123 * Returns the currently being used item by the player.
1124 */
1125 public ItemStack getCurrentEquippedItem()
1126 {
1127 return this.inventory.getCurrentItem();
1128 }
1129
1130 /**
1131 * Destroys the currently equipped item from the player's inventory.
1132 */
1133 public void destroyCurrentEquippedItem()
1134 {
1135 ItemStack orig = getCurrentEquippedItem();
1136 this.inventory.setInventorySlotContents(this.inventory.currentItem, (ItemStack)null);
1137 MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(this, orig));
1138 }
1139
1140 /**
1141 * Returns the Y Offset of this entity.
1142 */
1143 public double getYOffset()
1144 {
1145 return (double)(this.yOffset - 0.5F);
1146 }
1147
1148 /**
1149 * Attacks for the player the targeted entity with the currently equipped item. The equipped item has hitEntity
1150 * called on it. Args: targetEntity
1151 */
1152 public void attackTargetEntityWithCurrentItem(Entity par1Entity)
1153 {
1154 if (MinecraftForge.EVENT_BUS.post(new AttackEntityEvent(this, par1Entity)))
1155 {
1156 return;
1157 }
1158 ItemStack stack = getCurrentEquippedItem();
1159 if (stack != null && stack.getItem().onLeftClickEntity(stack, this, par1Entity))
1160 {
1161 return;
1162 }
1163 if (par1Entity.canAttackWithItem())
1164 {
1165 int var2 = this.inventory.getDamageVsEntity(par1Entity);
1166
1167 if (this.isPotionActive(Potion.damageBoost))
1168 {
1169 var2 += 3 << this.getActivePotionEffect(Potion.damageBoost).getAmplifier();
1170 }
1171
1172 if (this.isPotionActive(Potion.weakness))
1173 {
1174 var2 -= 2 << this.getActivePotionEffect(Potion.weakness).getAmplifier();
1175 }
1176
1177 int var3 = 0;
1178 int var4 = 0;
1179
1180 if (par1Entity instanceof EntityLiving)
1181 {
1182 var4 = EnchantmentHelper.getEnchantmentModifierLiving(this, (EntityLiving)par1Entity);
1183 var3 += EnchantmentHelper.getKnockbackModifier(this, (EntityLiving)par1Entity);
1184 }
1185
1186 if (this.isSprinting())
1187 {
1188 ++var3;
1189 }
1190
1191 if (var2 > 0 || var4 > 0)
1192 {
1193 boolean var5 = this.fallDistance > 0.0F && !this.onGround && !this.isOnLadder() && !this.isInWater() && !this.isPotionActive(Potion.blindness) && this.ridingEntity == null && par1Entity instanceof EntityLiving;
1194
1195 if (var5)
1196 {
1197 var2 += this.rand.nextInt(var2 / 2 + 2);
1198 }
1199
1200 var2 += var4;
1201 boolean var6 = par1Entity.attackEntityFrom(DamageSource.causePlayerDamage(this), var2);
1202
1203 if (var6)
1204 {
1205 if (var3 > 0)
1206 {
1207 par1Entity.addVelocity((double)(-MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F) * (float)var3 * 0.5F), 0.1D, (double)(MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F) * (float)var3 * 0.5F));
1208 this.motionX *= 0.6D;
1209 this.motionZ *= 0.6D;
1210 this.setSprinting(false);
1211 }
1212
1213 if (var5)
1214 {
1215 this.onCriticalHit(par1Entity);
1216 }
1217
1218 if (var4 > 0)
1219 {
1220 this.onEnchantmentCritical(par1Entity);
1221 }
1222
1223 if (var2 >= 18)
1224 {
1225 this.triggerAchievement(AchievementList.overkill);
1226 }
1227
1228 this.setLastAttackingEntity(par1Entity);
1229 }
1230
1231 ItemStack var7 = this.getCurrentEquippedItem();
1232
1233 if (var7 != null && par1Entity instanceof EntityLiving)
1234 {
1235 var7.hitEntity((EntityLiving)par1Entity, this);
1236
1237 if (var7.stackSize <= 0)
1238 {
1239 this.destroyCurrentEquippedItem();
1240 }
1241 }
1242
1243 if (par1Entity instanceof EntityLiving)
1244 {
1245 if (par1Entity.isEntityAlive())
1246 {
1247 this.alertWolves((EntityLiving)par1Entity, true);
1248 }
1249
1250 this.addStat(StatList.damageDealtStat, var2);
1251 int var8 = EnchantmentHelper.getFireAspectModifier(this, (EntityLiving)par1Entity);
1252
1253 if (var8 > 0 && var6)
1254 {
1255 par1Entity.setFire(var8 * 4);
1256 }
1257 }
1258
1259 this.addExhaustion(0.3F);
1260 }
1261 }
1262 }
1263
1264 /**
1265 * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically
1266 */
1267 public void onCriticalHit(Entity par1Entity) {}
1268
1269 public void onEnchantmentCritical(Entity par1Entity) {}
1270
1271 @SideOnly(Side.CLIENT)
1272 public void respawnPlayer() {}
1273
1274 /**
1275 * Will get destroyed next tick.
1276 */
1277 public void setDead()
1278 {
1279 super.setDead();
1280 this.inventorySlots.onCraftGuiClosed(this);
1281
1282 if (this.craftingInventory != null)
1283 {
1284 this.craftingInventory.onCraftGuiClosed(this);
1285 }
1286 }
1287
1288 /**
1289 * Checks if this entity is inside of an opaque block
1290 */
1291 public boolean isEntityInsideOpaqueBlock()
1292 {
1293 return !this.sleeping && super.isEntityInsideOpaqueBlock();
1294 }
1295
1296 public boolean func_71066_bF()
1297 {
1298 return false;
1299 }
1300
1301 /**
1302 * Attempts to have the player sleep in a bed at the specified location.
1303 */
1304 public EnumStatus sleepInBedAt(int par1, int par2, int par3)
1305 {
1306 PlayerSleepInBedEvent event = new PlayerSleepInBedEvent(this, par1, par2, par3);
1307 MinecraftForge.EVENT_BUS.post(event);
1308 if (event.result != null)
1309 {
1310 return event.result;
1311 }
1312 if (!this.worldObj.isRemote)
1313 {
1314 if (this.isPlayerSleeping() || !this.isEntityAlive())
1315 {
1316 return EnumStatus.OTHER_PROBLEM;
1317 }
1318
1319 if (!this.worldObj.provider.isSurfaceWorld())
1320 {
1321 return EnumStatus.NOT_POSSIBLE_HERE;
1322 }
1323
1324 if (this.worldObj.isDaytime())
1325 {
1326 return EnumStatus.NOT_POSSIBLE_NOW;
1327 }
1328
1329 if (Math.abs(this.posX - (double)par1) > 3.0D || Math.abs(this.posY - (double)par2) > 2.0D || Math.abs(this.posZ - (double)par3) > 3.0D)
1330 {
1331 return EnumStatus.TOO_FAR_AWAY;
1332 }
1333
1334 double var4 = 8.0D;
1335 double var6 = 5.0D;
1336 List var8 = this.worldObj.getEntitiesWithinAABB(EntityMob.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)par1 - var4, (double)par2 - var6, (double)par3 - var4, (double)par1 + var4, (double)par2 + var6, (double)par3 + var4));
1337
1338 if (!var8.isEmpty())
1339 {
1340 return EnumStatus.NOT_SAFE;
1341 }
1342 }
1343
1344 this.setSize(0.2F, 0.2F);
1345 this.yOffset = 0.2F;
1346
1347 if (this.worldObj.blockExists(par1, par2, par3))
1348 {
1349 int var9 = this.worldObj.getBlockMetadata(par1, par2, par3);
1350 int var5 = BlockBed.getDirection(var9);
1351 Block block = Block.blocksList[worldObj.getBlockId(par1, par2, par3)];
1352 if (block != null)
1353 {
1354 var5 = block.getBedDirection(worldObj, par1, par2, par3);
1355 }
1356 float var10 = 0.5F;
1357 float var7 = 0.5F;
1358
1359 switch (var5)
1360 {
1361 case 0:
1362 var7 = 0.9F;
1363 break;
1364 case 1:
1365 var10 = 0.1F;
1366 break;
1367 case 2:
1368 var7 = 0.1F;
1369 break;
1370 case 3:
1371 var10 = 0.9F;
1372 }
1373
1374 this.func_71013_b(var5);
1375 this.setPosition((double)((float)par1 + var10), (double)((float)par2 + 0.9375F), (double)((float)par3 + var7));
1376 }
1377 else
1378 {
1379 this.setPosition((double)((float)par1 + 0.5F), (double)((float)par2 + 0.9375F), (double)((float)par3 + 0.5F));
1380 }
1381
1382 this.sleeping = true;
1383 this.sleepTimer = 0;
1384 this.playerLocation = new ChunkCoordinates(par1, par2, par3);
1385 this.motionX = this.motionZ = this.motionY = 0.0D;
1386
1387 if (!this.worldObj.isRemote)
1388 {
1389 this.worldObj.updateAllPlayersSleepingFlag();
1390 }
1391
1392 return EnumStatus.OK;
1393 }
1394
1395 private void func_71013_b(int par1)
1396 {
1397 this.field_71079_bU = 0.0F;
1398 this.field_71089_bV = 0.0F;
1399
1400 switch (par1)
1401 {
1402 case 0:
1403 this.field_71089_bV = -1.8F;
1404 break;
1405 case 1:
1406 this.field_71079_bU = 1.8F;
1407 break;
1408 case 2:
1409 this.field_71089_bV = 1.8F;
1410 break;
1411 case 3:
1412 this.field_71079_bU = -1.8F;
1413 }
1414 }
1415
1416 /**
1417 * Wake up the player if they're sleeping.
1418 */
1419 public void wakeUpPlayer(boolean par1, boolean par2, boolean par3)
1420 {
1421 this.setSize(0.6F, 1.8F);
1422 this.resetHeight();
1423 ChunkCoordinates var4 = this.playerLocation;
1424 ChunkCoordinates var5 = this.playerLocation;
1425
1426 Block block = (var4 == null ? null : Block.blocksList[worldObj.getBlockId(var4.posX, var4.posY, var4.posZ)]);
1427
1428 if (var4 != null && block != null && block.isBed(worldObj, var4.posX, var4.posY, var4.posZ, this))
1429 {
1430 block.setBedOccupied(this.worldObj, var4.posX, var4.posY, var4.posZ, this, false);
1431 var5 = block.getBedSpawnPosition(worldObj, var4.posX, var4.posY, var4.posZ, this);
1432
1433 if (var5 == null)
1434 {
1435 var5 = new ChunkCoordinates(var4.posX, var4.posY + 1, var4.posZ);
1436 }
1437
1438 this.setPosition((double)((float)var5.posX + 0.5F), (double)((float)var5.posY + this.yOffset + 0.1F), (double)((float)var5.posZ + 0.5F));
1439 }
1440
1441 this.sleeping = false;
1442
1443 if (!this.worldObj.isRemote && par2)
1444 {
1445 this.worldObj.updateAllPlayersSleepingFlag();
1446 }
1447
1448 if (par1)
1449 {
1450 this.sleepTimer = 0;
1451 }
1452 else
1453 {
1454 this.sleepTimer = 100;
1455 }
1456
1457 if (par3)
1458 {
1459 this.setSpawnChunk(this.playerLocation, false);
1460 }
1461 }
1462
1463 /**
1464 * Checks if the player is currently in a bed
1465 */
1466 private boolean isInBed()
1467 {
1468 ChunkCoordinates c = playerLocation;
1469 int blockID = worldObj.getBlockId(c.posX, c.posY, c.posZ);
1470 return Block.blocksList[blockID] != null && Block.blocksList[blockID].isBed(worldObj, c.posX, c.posY, c.posZ, this);
1471 }
1472
1473 /**
1474 * Ensure that a block enabling respawning exists at the specified coordinates and find an empty space nearby to
1475 * spawn.
1476 */
1477 public static ChunkCoordinates verifyRespawnCoordinates(World par0World, ChunkCoordinates par1ChunkCoordinates, boolean par2)
1478 {
1479 IChunkProvider var3 = par0World.getChunkProvider();
1480 var3.loadChunk(par1ChunkCoordinates.posX - 3 >> 4, par1ChunkCoordinates.posZ - 3 >> 4);
1481 var3.loadChunk(par1ChunkCoordinates.posX + 3 >> 4, par1ChunkCoordinates.posZ - 3 >> 4);
1482 var3.loadChunk(par1ChunkCoordinates.posX - 3 >> 4, par1ChunkCoordinates.posZ + 3 >> 4);
1483 var3.loadChunk(par1ChunkCoordinates.posX + 3 >> 4, par1ChunkCoordinates.posZ + 3 >> 4);
1484
1485 ChunkCoordinates c = par1ChunkCoordinates;
1486 Block block = Block.blocksList[par0World.getBlockId(c.posX, c.posY, c.posZ)];
1487
1488 if (block == null || !block.isBed(par0World, c.posX, c.posY, c.posZ, null))
1489 {
1490 return par2 && par0World.isAirBlock(par1ChunkCoordinates.posX, par1ChunkCoordinates.posY, par1ChunkCoordinates.posZ) && par0World.isAirBlock(par1ChunkCoordinates.posX, par1ChunkCoordinates.posY + 1, par1ChunkCoordinates.posZ) ? par1ChunkCoordinates : null;
1491 }
1492 else
1493 {
1494 ChunkCoordinates var4 = block.getBedSpawnPosition(par0World, c.posX, c.posY, c.posZ, null);
1495 return var4;
1496 }
1497 }
1498
1499 @SideOnly(Side.CLIENT)
1500
1501 /**
1502 * Returns the orientation of the bed in degrees.
1503 */
1504 public float getBedOrientationInDegrees()
1505 {
1506 if (this.playerLocation != null)
1507 {
1508 int x = playerLocation.posX;
1509 int y = playerLocation.posY;
1510 int z = playerLocation.posZ;
1511 Block block = Block.blocksList[worldObj.getBlockId(x, y, z)];
1512 int var2 = (block == null ? 0 : block.getBedDirection(worldObj, x, y, z));
1513
1514 switch (var2)
1515 {
1516 case 0:
1517 return 90.0F;
1518 case 1:
1519 return 0.0F;
1520 case 2:
1521 return 270.0F;
1522 case 3:
1523 return 180.0F;
1524 }
1525 }
1526
1527 return 0.0F;
1528 }
1529
1530 /**
1531 * Returns whether player is sleeping or not
1532 */
1533 public boolean isPlayerSleeping()
1534 {
1535 return this.sleeping;
1536 }
1537
1538 /**
1539 * Returns whether or not the player is asleep and the screen has fully faded.
1540 */
1541 public boolean isPlayerFullyAsleep()
1542 {
1543 return this.sleeping && this.sleepTimer >= 100;
1544 }
1545
1546 @SideOnly(Side.CLIENT)
1547 public int getSleepTimer()
1548 {
1549 return this.sleepTimer;
1550 }
1551
1552 @SideOnly(Side.CLIENT)
1553 protected boolean func_82241_s(int par1)
1554 {
1555 return (this.dataWatcher.getWatchableObjectByte(16) & 1 << par1) != 0;
1556 }
1557
1558 protected void func_82239_b(int par1, boolean par2)
1559 {
1560 byte var3 = this.dataWatcher.getWatchableObjectByte(16);
1561
1562 if (par2)
1563 {
1564 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var3 | 1 << par1)));
1565 }
1566 else
1567 {
1568 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var3 & ~(1 << par1))));
1569 }
1570 }
1571
1572 /**
1573 * Add a chat message to the player
1574 */
1575 public void addChatMessage(String par1Str) {}
1576
1577 /**
1578 * Returns the coordinates to respawn the player based on last bed that the player sleep.
1579 */
1580 public ChunkCoordinates getSpawnChunk()
1581 {
1582 return this.spawnChunk;
1583 }
1584
1585 public boolean func_82245_bX()
1586 {
1587 return this.field_82248_d;
1588 }
1589
1590 /**
1591 * Defines a spawn coordinate to player spawn. Used by bed after the player sleep on it.
1592 */
1593 public void setSpawnChunk(ChunkCoordinates par1ChunkCoordinates, boolean par2)
1594 {
1595 if (par1ChunkCoordinates != null)
1596 {
1597 this.spawnChunk = new ChunkCoordinates(par1ChunkCoordinates);
1598 this.field_82248_d = par2;
1599 }
1600 else
1601 {
1602 this.spawnChunk = null;
1603 this.field_82248_d = false;
1604 }
1605 }
1606
1607 /**
1608 * Will trigger the specified trigger.
1609 */
1610 public void triggerAchievement(StatBase par1StatBase)
1611 {
1612 this.addStat(par1StatBase, 1);
1613 }
1614
1615 /**
1616 * Adds a value to a statistic field.
1617 */
1618 public void addStat(StatBase par1StatBase, int par2) {}
1619
1620 /**
1621 * Causes this entity to do an upwards motion (jumping).
1622 */
1623 protected void jump()
1624 {
1625 super.jump();
1626 this.addStat(StatList.jumpStat, 1);
1627
1628 if (this.isSprinting())
1629 {
1630 this.addExhaustion(0.8F);
1631 }
1632 else
1633 {
1634 this.addExhaustion(0.2F);
1635 }
1636 }
1637
1638 /**
1639 * Moves the entity based on the specified heading. Args: strafe, forward
1640 */
1641 public void moveEntityWithHeading(float par1, float par2)
1642 {
1643 double var3 = this.posX;
1644 double var5 = this.posY;
1645 double var7 = this.posZ;
1646
1647 if (this.capabilities.isFlying && this.ridingEntity == null)
1648 {
1649 double var9 = this.motionY;
1650 float var11 = this.jumpMovementFactor;
1651 this.jumpMovementFactor = this.capabilities.getFlySpeed();
1652 super.moveEntityWithHeading(par1, par2);
1653 this.motionY = var9 * 0.6D;
1654 this.jumpMovementFactor = var11;
1655 }
1656 else
1657 {
1658 super.moveEntityWithHeading(par1, par2);
1659 }
1660
1661 this.addMovementStat(this.posX - var3, this.posY - var5, this.posZ - var7);
1662 }
1663
1664 /**
1665 * Adds a value to a movement statistic field - like run, walk, swin or climb.
1666 */
1667 public void addMovementStat(double par1, double par3, double par5)
1668 {
1669 if (this.ridingEntity == null)
1670 {
1671 int var7;
1672
1673 if (this.isInsideOfMaterial(Material.water))
1674 {
1675 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5) * 100.0F);
1676
1677 if (var7 > 0)
1678 {
1679 this.addStat(StatList.distanceDoveStat, var7);
1680 this.addExhaustion(0.015F * (float)var7 * 0.01F);
1681 }
1682 }
1683 else if (this.isInWater())
1684 {
1685 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1686
1687 if (var7 > 0)
1688 {
1689 this.addStat(StatList.distanceSwumStat, var7);
1690 this.addExhaustion(0.015F * (float)var7 * 0.01F);
1691 }
1692 }
1693 else if (this.isOnLadder())
1694 {
1695 if (par3 > 0.0D)
1696 {
1697 this.addStat(StatList.distanceClimbedStat, (int)Math.round(par3 * 100.0D));
1698 }
1699 }
1700 else if (this.onGround)
1701 {
1702 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1703
1704 if (var7 > 0)
1705 {
1706 this.addStat(StatList.distanceWalkedStat, var7);
1707
1708 if (this.isSprinting())
1709 {
1710 this.addExhaustion(0.099999994F * (float)var7 * 0.01F);
1711 }
1712 else
1713 {
1714 this.addExhaustion(0.01F * (float)var7 * 0.01F);
1715 }
1716 }
1717 }
1718 else
1719 {
1720 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1721
1722 if (var7 > 25)
1723 {
1724 this.addStat(StatList.distanceFlownStat, var7);
1725 }
1726 }
1727 }
1728 }
1729
1730 /**
1731 * Adds a value to a mounted movement statistic field - by minecart, boat, or pig.
1732 */
1733 private void addMountedMovementStat(double par1, double par3, double par5)
1734 {
1735 if (this.ridingEntity != null)
1736 {
1737 int var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5) * 100.0F);
1738
1739 if (var7 > 0)
1740 {
1741 if (this.ridingEntity instanceof EntityMinecart)
1742 {
1743 this.addStat(StatList.distanceByMinecartStat, var7);
1744
1745 if (this.startMinecartRidingCoordinate == null)
1746 {
1747 this.startMinecartRidingCoordinate = new ChunkCoordinates(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
1748 }
1749 else if ((double)this.startMinecartRidingCoordinate.getDistanceSquared(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) >= 1000000.0D)
1750 {
1751 this.addStat(AchievementList.onARail, 1);
1752 }
1753 }
1754 else if (this.ridingEntity instanceof EntityBoat)
1755 {
1756 this.addStat(StatList.distanceByBoatStat, var7);
1757 }
1758 else if (this.ridingEntity instanceof EntityPig)
1759 {
1760 this.addStat(StatList.distanceByPigStat, var7);
1761 }
1762 }
1763 }
1764 }
1765
1766 /**
1767 * Called when the mob is falling. Calculates and applies fall damage.
1768 */
1769 protected void fall(float par1)
1770 {
1771 if (!this.capabilities.allowFlying)
1772 {
1773 if (par1 >= 2.0F)
1774 {
1775 this.addStat(StatList.distanceFallenStat, (int)Math.round((double)par1 * 100.0D));
1776 }
1777
1778 super.fall(par1);
1779 }
1780 }
1781
1782 /**
1783 * This method gets called when the entity kills another one.
1784 */
1785 public void onKillEntity(EntityLiving par1EntityLiving)
1786 {
1787 if (par1EntityLiving instanceof IMob)
1788 {
1789 this.triggerAchievement(AchievementList.killEnemy);
1790 }
1791 }
1792
1793 @SideOnly(Side.CLIENT)
1794
1795 /**
1796 * Gets the Icon Index of the item currently held
1797 */
1798 public int getItemIcon(ItemStack par1ItemStack, int par2)
1799 {
1800 int var3 = super.getItemIcon(par1ItemStack, par2);
1801
1802 if (par1ItemStack.itemID == Item.fishingRod.shiftedIndex && this.fishEntity != null)
1803 {
1804 var3 = par1ItemStack.getIconIndex() + 16;
1805 }
1806 else
1807 {
1808 if (par1ItemStack.getItem().requiresMultipleRenderPasses())
1809 {
1810 return par1ItemStack.getItem().getIconFromDamageForRenderPass(par1ItemStack.getItemDamage(), par2);
1811 }
1812
1813 if (this.itemInUse != null && par1ItemStack.itemID == Item.bow.shiftedIndex)
1814 {
1815 int var4 = par1ItemStack.getMaxItemUseDuration() - this.itemInUseCount;
1816
1817 if (var4 >= 18)
1818 {
1819 return 133;
1820 }
1821
1822 if (var4 > 13)
1823 {
1824 return 117;
1825 }
1826
1827 if (var4 > 0)
1828 {
1829 return 101;
1830 }
1831 }
1832 var3 = par1ItemStack.getItem().getIconIndex(par1ItemStack, par2, this, itemInUse, itemInUseCount);
1833 }
1834
1835 return var3;
1836 }
1837
1838 public ItemStack func_82169_q(int par1)
1839 {
1840 return this.inventory.armorItemInSlot(par1);
1841 }
1842
1843 protected void func_82164_bB() {}
1844
1845 protected void func_82162_bC() {}
1846
1847 /**
1848 * This method increases the player's current amount of experience.
1849 */
1850 public void addExperience(int par1)
1851 {
1852 this.score += par1;
1853 int var2 = Integer.MAX_VALUE - this.experienceTotal;
1854
1855 if (par1 > var2)
1856 {
1857 par1 = var2;
1858 }
1859
1860 this.experience += (float)par1 / (float)this.xpBarCap();
1861
1862 for (this.experienceTotal += par1; this.experience >= 1.0F; this.experience /= (float)this.xpBarCap())
1863 {
1864 this.experience = (this.experience - 1.0F) * (float)this.xpBarCap();
1865 this.func_82242_a(1);
1866 }
1867 }
1868
1869 public void func_82242_a(int par1)
1870 {
1871 this.experienceLevel += par1;
1872
1873 if (this.experienceLevel < 0)
1874 {
1875 this.experienceLevel = 0;
1876 }
1877
1878 if (par1 > 0 && this.experienceLevel % 5 == 0 && (float)this.field_82249_h < (float)this.ticksExisted - 100.0F)
1879 {
1880 float var2 = this.experienceLevel > 30 ? 1.0F : (float)this.experienceLevel / 30.0F;
1881 this.worldObj.playSoundAtEntity(this, "random.levelup", var2 * 0.75F, 1.0F);
1882 this.field_82249_h = this.ticksExisted;
1883 }
1884 }
1885
1886 /**
1887 * This method returns the cap amount of experience that the experience bar can hold. With each level, the
1888 * experience cap on the player's experience bar is raised by 10.
1889 */
1890 public int xpBarCap()
1891 {
1892 return this.experienceLevel >= 30 ? 62 + (this.experienceLevel - 30) * 7 : (this.experienceLevel >= 15 ? 17 + (this.experienceLevel - 15) * 3 : 17);
1893 }
1894
1895 /**
1896 * increases exhaustion level by supplied amount
1897 */
1898 public void addExhaustion(float par1)
1899 {
1900 if (!this.capabilities.disableDamage)
1901 {
1902 if (!this.worldObj.isRemote)
1903 {
1904 this.foodStats.addExhaustion(par1);
1905 }
1906 }
1907 }
1908
1909 /**
1910 * Returns the player's FoodStats object.
1911 */
1912 public FoodStats getFoodStats()
1913 {
1914 return this.foodStats;
1915 }
1916
1917 public boolean canEat(boolean par1)
1918 {
1919 return (par1 || this.foodStats.needFood()) && !this.capabilities.disableDamage;
1920 }
1921
1922 /**
1923 * Checks if the player's health is not full and not zero.
1924 */
1925 public boolean shouldHeal()
1926 {
1927 return this.getHealth() > 0 && this.getHealth() < this.getMaxHealth();
1928 }
1929
1930 /**
1931 * sets the itemInUse when the use item button is clicked. Args: itemstack, int maxItemUseDuration
1932 */
1933 public void setItemInUse(ItemStack par1ItemStack, int par2)
1934 {
1935 if (par1ItemStack != this.itemInUse)
1936 {
1937 this.itemInUse = par1ItemStack;
1938 this.itemInUseCount = par2;
1939
1940 if (!this.worldObj.isRemote)
1941 {
1942 this.setEating(true);
1943 }
1944 }
1945 }
1946
1947 public boolean func_82246_f(int par1, int par2, int par3)
1948 {
1949 if (this.capabilities.allowEdit)
1950 {
1951 return true;
1952 }
1953 else
1954 {
1955 int var4 = this.worldObj.getBlockId(par1, par2, par3);
1956
1957 if (var4 > 0 && this.getCurrentEquippedItem() != null)
1958 {
1959 Block var5 = Block.blocksList[var4];
1960 ItemStack var6 = this.getCurrentEquippedItem();
1961
1962 if (var6.canHarvestBlock(var5) || var6.getStrVsBlock(var5) > 1.0F)
1963 {
1964 return true;
1965 }
1966 }
1967
1968 return false;
1969 }
1970 }
1971
1972 public boolean func_82247_a(int par1, int par2, int par3, int par4, ItemStack par5ItemStack)
1973 {
1974 return this.capabilities.allowEdit ? true : (par5ItemStack != null ? par5ItemStack.func_82835_x() : false);
1975 }
1976
1977 /**
1978 * Get the experience points the entity currently has.
1979 */
1980 protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
1981 {
1982 if (this.worldObj.func_82736_K().func_82766_b("keepInventory"))
1983 {
1984 return 0;
1985 }
1986 else
1987 {
1988 int var2 = this.experienceLevel * 7;
1989 return var2 > 100 ? 100 : var2;
1990 }
1991 }
1992
1993 /**
1994 * Only use is to identify if class is an instance of player for experience dropping
1995 */
1996 protected boolean isPlayer()
1997 {
1998 return true;
1999 }
2000
2001 /**
2002 * Gets the username of the entity.
2003 */
2004 public String getEntityName()
2005 {
2006 return this.username;
2007 }
2008
2009 /**
2010 * Copies the values from the given player into this player if boolean par2 is true. Always clones Ender Chest
2011 * Inventory.
2012 */
2013 public void clonePlayer(EntityPlayer par1EntityPlayer, boolean par2)
2014 {
2015 if (par2)
2016 {
2017 this.inventory.copyInventory(par1EntityPlayer.inventory);
2018 this.health = par1EntityPlayer.health;
2019 this.foodStats = par1EntityPlayer.foodStats;
2020 this.experienceLevel = par1EntityPlayer.experienceLevel;
2021 this.experienceTotal = par1EntityPlayer.experienceTotal;
2022 this.experience = par1EntityPlayer.experience;
2023 this.score = par1EntityPlayer.score;
2024 this.field_82152_aq = par1EntityPlayer.field_82152_aq;
2025 }
2026 else if (this.worldObj.func_82736_K().func_82766_b("keepInventory"))
2027 {
2028 this.inventory.copyInventory(par1EntityPlayer.inventory);
2029 this.experienceLevel = par1EntityPlayer.experienceLevel;
2030 this.experienceTotal = par1EntityPlayer.experienceTotal;
2031 this.experience = par1EntityPlayer.experience;
2032 this.score = par1EntityPlayer.score;
2033 }
2034
2035 this.theInventoryEnderChest = par1EntityPlayer.theInventoryEnderChest;
2036 }
2037
2038 /**
2039 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
2040 * prevent them from trampling crops
2041 */
2042 protected boolean canTriggerWalking()
2043 {
2044 return !this.capabilities.isFlying;
2045 }
2046
2047 /**
2048 * Sends the player's abilities to the server (if there is one).
2049 */
2050 public void sendPlayerAbilities() {}
2051
2052 public void sendGameTypeToPlayer(EnumGameType par1EnumGameType) {}
2053
2054 /**
2055 * Gets the name of this command sender (usually username, but possibly "Rcon")
2056 */
2057 public String getCommandSenderName()
2058 {
2059 return this.username;
2060 }
2061
2062 public StringTranslate getTranslator()
2063 {
2064 return StringTranslate.getInstance();
2065 }
2066
2067 /**
2068 * Translates and formats the given string key with the given arguments.
2069 */
2070 public String translateString(String par1Str, Object ... par2ArrayOfObj)
2071 {
2072 return this.getTranslator().translateKeyFormat(par1Str, par2ArrayOfObj);
2073 }
2074
2075 /**
2076 * Returns the InventoryEnderChest of this player.
2077 */
2078 public InventoryEnderChest getInventoryEnderChest()
2079 {
2080 return this.theInventoryEnderChest;
2081 }
2082
2083 /**
2084 * 0 = item, 1-n is armor
2085 */
2086 public ItemStack getCurrentItemOrArmor(int par1)
2087 {
2088 return par1 == 0 ? this.inventory.getCurrentItem() : this.inventory.armorInventory[par1 - 1];
2089 }
2090
2091 /**
2092 * Returns the item that this EntityLiving is holding, if any.
2093 */
2094 public ItemStack getHeldItem()
2095 {
2096 return this.inventory.getCurrentItem();
2097 }
2098
2099 public void func_70062_b(int par1, ItemStack par2ItemStack)
2100 {
2101 this.inventory.armorInventory[par1] = par2ItemStack;
2102 }
2103
2104 public ItemStack[] getLastActiveItems()
2105 {
2106 return this.inventory.armorInventory;
2107 }
2108
2109 @SideOnly(Side.CLIENT)
2110 public boolean func_82238_cc()
2111 {
2112 return this.func_82241_s(1);
2113 }
2114
2115 public void openGui(Object mod, int modGuiId, World world, int x, int y, int z)
2116 {
2117 FMLNetworkHandler.openGui(this, mod, modGuiId, world, x, y, z);
2118 }
2119 }