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