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 if (!this.field_83001_bt)
1036 {
1037 par2 = ForgeHooks.onLivingHurt(this, par1DamageSource, par2);
1038 if (par2 <= 0)
1039 {
1040 return;
1041 }
1042
1043 if (!par1DamageSource.isUnblockable() && this.isBlocking())
1044 {
1045 par2 = 1 + par2 >> 1;
1046 }
1047
1048 par2 = ArmorProperties.ApplyArmor(this, inventory.armorInventory, par1DamageSource, par2);
1049 if (par2 <= 0)
1050 {
1051 return;
1052 }
1053 par2 = this.applyPotionDamageCalculations(par1DamageSource, par2);
1054 this.addExhaustion(par1DamageSource.getHungerDamage());
1055 this.health -= par2;
1056 }
1057 }
1058
1059 /**
1060 * Displays the furnace GUI for the passed in furnace entity. Args: tileEntityFurnace
1061 */
1062 public void displayGUIFurnace(TileEntityFurnace par1TileEntityFurnace) {}
1063
1064 /**
1065 * Displays the dipsenser GUI for the passed in dispenser entity. Args: TileEntityDispenser
1066 */
1067 public void displayGUIDispenser(TileEntityDispenser par1TileEntityDispenser) {}
1068
1069 /**
1070 * Displays the GUI for editing a sign. Args: tileEntitySign
1071 */
1072 public void displayGUIEditSign(TileEntity par1TileEntity) {}
1073
1074 /**
1075 * Displays the GUI for interacting with a brewing stand.
1076 */
1077 public void displayGUIBrewingStand(TileEntityBrewingStand par1TileEntityBrewingStand) {}
1078
1079 public void func_82240_a(TileEntityBeacon par1TileEntityBeacon) {}
1080
1081 public void displayGUIMerchant(IMerchant par1IMerchant) {}
1082
1083 /**
1084 * Displays the GUI for interacting with a book.
1085 */
1086 public void displayGUIBook(ItemStack par1ItemStack) {}
1087
1088 public boolean interactWith(Entity par1Entity)
1089 {
1090 if (MinecraftForge.EVENT_BUS.post(new EntityInteractEvent(this, par1Entity)))
1091 {
1092 return false;
1093 }
1094 if (par1Entity.interact(this))
1095 {
1096 return true;
1097 }
1098 else
1099 {
1100 ItemStack var2 = this.getCurrentEquippedItem();
1101
1102 if (var2 != null && par1Entity instanceof EntityLiving)
1103 {
1104 if (this.capabilities.isCreativeMode)
1105 {
1106 var2 = var2.copy();
1107 }
1108
1109 if (var2.interactWith((EntityLiving)par1Entity))
1110 {
1111 if (var2.stackSize <= 0 && !this.capabilities.isCreativeMode)
1112 {
1113 this.destroyCurrentEquippedItem();
1114 }
1115
1116 return true;
1117 }
1118 }
1119
1120 return false;
1121 }
1122 }
1123
1124 /**
1125 * Returns the currently being used item by the player.
1126 */
1127 public ItemStack getCurrentEquippedItem()
1128 {
1129 return this.inventory.getCurrentItem();
1130 }
1131
1132 /**
1133 * Destroys the currently equipped item from the player's inventory.
1134 */
1135 public void destroyCurrentEquippedItem()
1136 {
1137 ItemStack orig = getCurrentEquippedItem();
1138 this.inventory.setInventorySlotContents(this.inventory.currentItem, (ItemStack)null);
1139 MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(this, orig));
1140 }
1141
1142 /**
1143 * Returns the Y Offset of this entity.
1144 */
1145 public double getYOffset()
1146 {
1147 return (double)(this.yOffset - 0.5F);
1148 }
1149
1150 /**
1151 * Attacks for the player the targeted entity with the currently equipped item. The equipped item has hitEntity
1152 * called on it. Args: targetEntity
1153 */
1154 public void attackTargetEntityWithCurrentItem(Entity par1Entity)
1155 {
1156 if (MinecraftForge.EVENT_BUS.post(new AttackEntityEvent(this, par1Entity)))
1157 {
1158 return;
1159 }
1160 ItemStack stack = getCurrentEquippedItem();
1161 if (stack != null && stack.getItem().onLeftClickEntity(stack, this, par1Entity))
1162 {
1163 return;
1164 }
1165 if (par1Entity.canAttackWithItem())
1166 {
1167 int var2 = this.inventory.getDamageVsEntity(par1Entity);
1168
1169 if (this.isPotionActive(Potion.damageBoost))
1170 {
1171 var2 += 3 << this.getActivePotionEffect(Potion.damageBoost).getAmplifier();
1172 }
1173
1174 if (this.isPotionActive(Potion.weakness))
1175 {
1176 var2 -= 2 << this.getActivePotionEffect(Potion.weakness).getAmplifier();
1177 }
1178
1179 int var3 = 0;
1180 int var4 = 0;
1181
1182 if (par1Entity instanceof EntityLiving)
1183 {
1184 var4 = EnchantmentHelper.getEnchantmentModifierLiving(this, (EntityLiving)par1Entity);
1185 var3 += EnchantmentHelper.getKnockbackModifier(this, (EntityLiving)par1Entity);
1186 }
1187
1188 if (this.isSprinting())
1189 {
1190 ++var3;
1191 }
1192
1193 if (var2 > 0 || var4 > 0)
1194 {
1195 boolean var5 = this.fallDistance > 0.0F && !this.onGround && !this.isOnLadder() && !this.isInWater() && !this.isPotionActive(Potion.blindness) && this.ridingEntity == null && par1Entity instanceof EntityLiving;
1196
1197 if (var5)
1198 {
1199 var2 += this.rand.nextInt(var2 / 2 + 2);
1200 }
1201
1202 var2 += var4;
1203 boolean var6 = par1Entity.attackEntityFrom(DamageSource.causePlayerDamage(this), var2);
1204
1205 if (var6)
1206 {
1207 if (var3 > 0)
1208 {
1209 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));
1210 this.motionX *= 0.6D;
1211 this.motionZ *= 0.6D;
1212 this.setSprinting(false);
1213 }
1214
1215 if (var5)
1216 {
1217 this.onCriticalHit(par1Entity);
1218 }
1219
1220 if (var4 > 0)
1221 {
1222 this.onEnchantmentCritical(par1Entity);
1223 }
1224
1225 if (var2 >= 18)
1226 {
1227 this.triggerAchievement(AchievementList.overkill);
1228 }
1229
1230 this.setLastAttackingEntity(par1Entity);
1231 }
1232
1233 ItemStack var7 = this.getCurrentEquippedItem();
1234
1235 if (var7 != null && par1Entity instanceof EntityLiving)
1236 {
1237 var7.hitEntity((EntityLiving)par1Entity, this);
1238
1239 if (var7.stackSize <= 0)
1240 {
1241 this.destroyCurrentEquippedItem();
1242 }
1243 }
1244
1245 if (par1Entity instanceof EntityLiving)
1246 {
1247 if (par1Entity.isEntityAlive())
1248 {
1249 this.alertWolves((EntityLiving)par1Entity, true);
1250 }
1251
1252 this.addStat(StatList.damageDealtStat, var2);
1253 int var8 = EnchantmentHelper.getFireAspectModifier(this, (EntityLiving)par1Entity);
1254
1255 if (var8 > 0 && var6)
1256 {
1257 par1Entity.setFire(var8 * 4);
1258 }
1259 }
1260
1261 this.addExhaustion(0.3F);
1262 }
1263 }
1264 }
1265
1266 /**
1267 * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically
1268 */
1269 public void onCriticalHit(Entity par1Entity) {}
1270
1271 public void onEnchantmentCritical(Entity par1Entity) {}
1272
1273 @SideOnly(Side.CLIENT)
1274 public void respawnPlayer() {}
1275
1276 /**
1277 * Will get destroyed next tick.
1278 */
1279 public void setDead()
1280 {
1281 super.setDead();
1282 this.inventorySlots.onCraftGuiClosed(this);
1283
1284 if (this.craftingInventory != null)
1285 {
1286 this.craftingInventory.onCraftGuiClosed(this);
1287 }
1288 }
1289
1290 /**
1291 * Checks if this entity is inside of an opaque block
1292 */
1293 public boolean isEntityInsideOpaqueBlock()
1294 {
1295 return !this.sleeping && super.isEntityInsideOpaqueBlock();
1296 }
1297
1298 public boolean func_71066_bF()
1299 {
1300 return false;
1301 }
1302
1303 /**
1304 * Attempts to have the player sleep in a bed at the specified location.
1305 */
1306 public EnumStatus sleepInBedAt(int par1, int par2, int par3)
1307 {
1308 PlayerSleepInBedEvent event = new PlayerSleepInBedEvent(this, par1, par2, par3);
1309 MinecraftForge.EVENT_BUS.post(event);
1310 if (event.result != null)
1311 {
1312 return event.result;
1313 }
1314 if (!this.worldObj.isRemote)
1315 {
1316 if (this.isPlayerSleeping() || !this.isEntityAlive())
1317 {
1318 return EnumStatus.OTHER_PROBLEM;
1319 }
1320
1321 if (!this.worldObj.provider.isSurfaceWorld())
1322 {
1323 return EnumStatus.NOT_POSSIBLE_HERE;
1324 }
1325
1326 if (this.worldObj.isDaytime())
1327 {
1328 return EnumStatus.NOT_POSSIBLE_NOW;
1329 }
1330
1331 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)
1332 {
1333 return EnumStatus.TOO_FAR_AWAY;
1334 }
1335
1336 double var4 = 8.0D;
1337 double var6 = 5.0D;
1338 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));
1339
1340 if (!var8.isEmpty())
1341 {
1342 return EnumStatus.NOT_SAFE;
1343 }
1344 }
1345
1346 this.setSize(0.2F, 0.2F);
1347 this.yOffset = 0.2F;
1348
1349 if (this.worldObj.blockExists(par1, par2, par3))
1350 {
1351 int var9 = this.worldObj.getBlockMetadata(par1, par2, par3);
1352 int var5 = BlockBed.getDirection(var9);
1353 Block block = Block.blocksList[worldObj.getBlockId(par1, par2, par3)];
1354 if (block != null)
1355 {
1356 var5 = block.getBedDirection(worldObj, par1, par2, par3);
1357 }
1358 float var10 = 0.5F;
1359 float var7 = 0.5F;
1360
1361 switch (var5)
1362 {
1363 case 0:
1364 var7 = 0.9F;
1365 break;
1366 case 1:
1367 var10 = 0.1F;
1368 break;
1369 case 2:
1370 var7 = 0.1F;
1371 break;
1372 case 3:
1373 var10 = 0.9F;
1374 }
1375
1376 this.func_71013_b(var5);
1377 this.setPosition((double)((float)par1 + var10), (double)((float)par2 + 0.9375F), (double)((float)par3 + var7));
1378 }
1379 else
1380 {
1381 this.setPosition((double)((float)par1 + 0.5F), (double)((float)par2 + 0.9375F), (double)((float)par3 + 0.5F));
1382 }
1383
1384 this.sleeping = true;
1385 this.sleepTimer = 0;
1386 this.playerLocation = new ChunkCoordinates(par1, par2, par3);
1387 this.motionX = this.motionZ = this.motionY = 0.0D;
1388
1389 if (!this.worldObj.isRemote)
1390 {
1391 this.worldObj.updateAllPlayersSleepingFlag();
1392 }
1393
1394 return EnumStatus.OK;
1395 }
1396
1397 private void func_71013_b(int par1)
1398 {
1399 this.field_71079_bU = 0.0F;
1400 this.field_71089_bV = 0.0F;
1401
1402 switch (par1)
1403 {
1404 case 0:
1405 this.field_71089_bV = -1.8F;
1406 break;
1407 case 1:
1408 this.field_71079_bU = 1.8F;
1409 break;
1410 case 2:
1411 this.field_71089_bV = 1.8F;
1412 break;
1413 case 3:
1414 this.field_71079_bU = -1.8F;
1415 }
1416 }
1417
1418 /**
1419 * Wake up the player if they're sleeping.
1420 */
1421 public void wakeUpPlayer(boolean par1, boolean par2, boolean par3)
1422 {
1423 this.setSize(0.6F, 1.8F);
1424 this.resetHeight();
1425 ChunkCoordinates var4 = this.playerLocation;
1426 ChunkCoordinates var5 = this.playerLocation;
1427
1428 Block block = (var4 == null ? null : Block.blocksList[worldObj.getBlockId(var4.posX, var4.posY, var4.posZ)]);
1429
1430 if (var4 != null && block != null && block.isBed(worldObj, var4.posX, var4.posY, var4.posZ, this))
1431 {
1432 block.setBedOccupied(this.worldObj, var4.posX, var4.posY, var4.posZ, this, false);
1433 var5 = block.getBedSpawnPosition(worldObj, var4.posX, var4.posY, var4.posZ, this);
1434
1435 if (var5 == null)
1436 {
1437 var5 = new ChunkCoordinates(var4.posX, var4.posY + 1, var4.posZ);
1438 }
1439
1440 this.setPosition((double)((float)var5.posX + 0.5F), (double)((float)var5.posY + this.yOffset + 0.1F), (double)((float)var5.posZ + 0.5F));
1441 }
1442
1443 this.sleeping = false;
1444
1445 if (!this.worldObj.isRemote && par2)
1446 {
1447 this.worldObj.updateAllPlayersSleepingFlag();
1448 }
1449
1450 if (par1)
1451 {
1452 this.sleepTimer = 0;
1453 }
1454 else
1455 {
1456 this.sleepTimer = 100;
1457 }
1458
1459 if (par3)
1460 {
1461 this.setSpawnChunk(this.playerLocation, false);
1462 }
1463 }
1464
1465 /**
1466 * Checks if the player is currently in a bed
1467 */
1468 private boolean isInBed()
1469 {
1470 ChunkCoordinates c = playerLocation;
1471 int blockID = worldObj.getBlockId(c.posX, c.posY, c.posZ);
1472 return Block.blocksList[blockID] != null && Block.blocksList[blockID].isBed(worldObj, c.posX, c.posY, c.posZ, this);
1473 }
1474
1475 /**
1476 * Ensure that a block enabling respawning exists at the specified coordinates and find an empty space nearby to
1477 * spawn.
1478 */
1479 public static ChunkCoordinates verifyRespawnCoordinates(World par0World, ChunkCoordinates par1ChunkCoordinates, boolean par2)
1480 {
1481 IChunkProvider var3 = par0World.getChunkProvider();
1482 var3.loadChunk(par1ChunkCoordinates.posX - 3 >> 4, par1ChunkCoordinates.posZ - 3 >> 4);
1483 var3.loadChunk(par1ChunkCoordinates.posX + 3 >> 4, par1ChunkCoordinates.posZ - 3 >> 4);
1484 var3.loadChunk(par1ChunkCoordinates.posX - 3 >> 4, par1ChunkCoordinates.posZ + 3 >> 4);
1485 var3.loadChunk(par1ChunkCoordinates.posX + 3 >> 4, par1ChunkCoordinates.posZ + 3 >> 4);
1486
1487 ChunkCoordinates c = par1ChunkCoordinates;
1488 Block block = Block.blocksList[par0World.getBlockId(c.posX, c.posY, c.posZ)];
1489
1490 if (block == null || !block.isBed(par0World, c.posX, c.posY, c.posZ, null))
1491 {
1492 return par2 && par0World.isAirBlock(par1ChunkCoordinates.posX, par1ChunkCoordinates.posY, par1ChunkCoordinates.posZ) && par0World.isAirBlock(par1ChunkCoordinates.posX, par1ChunkCoordinates.posY + 1, par1ChunkCoordinates.posZ) ? par1ChunkCoordinates : null;
1493 }
1494 else
1495 {
1496 ChunkCoordinates var4 = block.getBedSpawnPosition(par0World, c.posX, c.posY, c.posZ, null);
1497 return var4;
1498 }
1499 }
1500
1501 @SideOnly(Side.CLIENT)
1502
1503 /**
1504 * Returns the orientation of the bed in degrees.
1505 */
1506 public float getBedOrientationInDegrees()
1507 {
1508 if (this.playerLocation != null)
1509 {
1510 int x = playerLocation.posX;
1511 int y = playerLocation.posY;
1512 int z = playerLocation.posZ;
1513 Block block = Block.blocksList[worldObj.getBlockId(x, y, z)];
1514 int var2 = (block == null ? 0 : block.getBedDirection(worldObj, x, y, z));
1515
1516 switch (var2)
1517 {
1518 case 0:
1519 return 90.0F;
1520 case 1:
1521 return 0.0F;
1522 case 2:
1523 return 270.0F;
1524 case 3:
1525 return 180.0F;
1526 }
1527 }
1528
1529 return 0.0F;
1530 }
1531
1532 /**
1533 * Returns whether player is sleeping or not
1534 */
1535 public boolean isPlayerSleeping()
1536 {
1537 return this.sleeping;
1538 }
1539
1540 /**
1541 * Returns whether or not the player is asleep and the screen has fully faded.
1542 */
1543 public boolean isPlayerFullyAsleep()
1544 {
1545 return this.sleeping && this.sleepTimer >= 100;
1546 }
1547
1548 @SideOnly(Side.CLIENT)
1549 public int getSleepTimer()
1550 {
1551 return this.sleepTimer;
1552 }
1553
1554 @SideOnly(Side.CLIENT)
1555 protected boolean func_82241_s(int par1)
1556 {
1557 return (this.dataWatcher.getWatchableObjectByte(16) & 1 << par1) != 0;
1558 }
1559
1560 protected void func_82239_b(int par1, boolean par2)
1561 {
1562 byte var3 = this.dataWatcher.getWatchableObjectByte(16);
1563
1564 if (par2)
1565 {
1566 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var3 | 1 << par1)));
1567 }
1568 else
1569 {
1570 this.dataWatcher.updateObject(16, Byte.valueOf((byte)(var3 & ~(1 << par1))));
1571 }
1572 }
1573
1574 /**
1575 * Add a chat message to the player
1576 */
1577 public void addChatMessage(String par1Str) {}
1578
1579 /**
1580 * Returns the coordinates to respawn the player based on last bed that the player sleep.
1581 */
1582 public ChunkCoordinates getSpawnChunk()
1583 {
1584 return this.spawnChunk;
1585 }
1586
1587 public boolean func_82245_bX()
1588 {
1589 return this.field_82248_d;
1590 }
1591
1592 /**
1593 * Defines a spawn coordinate to player spawn. Used by bed after the player sleep on it.
1594 */
1595 public void setSpawnChunk(ChunkCoordinates par1ChunkCoordinates, boolean par2)
1596 {
1597 if (par1ChunkCoordinates != null)
1598 {
1599 this.spawnChunk = new ChunkCoordinates(par1ChunkCoordinates);
1600 this.field_82248_d = par2;
1601 }
1602 else
1603 {
1604 this.spawnChunk = null;
1605 this.field_82248_d = false;
1606 }
1607 }
1608
1609 /**
1610 * Will trigger the specified trigger.
1611 */
1612 public void triggerAchievement(StatBase par1StatBase)
1613 {
1614 this.addStat(par1StatBase, 1);
1615 }
1616
1617 /**
1618 * Adds a value to a statistic field.
1619 */
1620 public void addStat(StatBase par1StatBase, int par2) {}
1621
1622 /**
1623 * Causes this entity to do an upwards motion (jumping).
1624 */
1625 protected void jump()
1626 {
1627 super.jump();
1628 this.addStat(StatList.jumpStat, 1);
1629
1630 if (this.isSprinting())
1631 {
1632 this.addExhaustion(0.8F);
1633 }
1634 else
1635 {
1636 this.addExhaustion(0.2F);
1637 }
1638 }
1639
1640 /**
1641 * Moves the entity based on the specified heading. Args: strafe, forward
1642 */
1643 public void moveEntityWithHeading(float par1, float par2)
1644 {
1645 double var3 = this.posX;
1646 double var5 = this.posY;
1647 double var7 = this.posZ;
1648
1649 if (this.capabilities.isFlying && this.ridingEntity == null)
1650 {
1651 double var9 = this.motionY;
1652 float var11 = this.jumpMovementFactor;
1653 this.jumpMovementFactor = this.capabilities.getFlySpeed();
1654 super.moveEntityWithHeading(par1, par2);
1655 this.motionY = var9 * 0.6D;
1656 this.jumpMovementFactor = var11;
1657 }
1658 else
1659 {
1660 super.moveEntityWithHeading(par1, par2);
1661 }
1662
1663 this.addMovementStat(this.posX - var3, this.posY - var5, this.posZ - var7);
1664 }
1665
1666 /**
1667 * Adds a value to a movement statistic field - like run, walk, swin or climb.
1668 */
1669 public void addMovementStat(double par1, double par3, double par5)
1670 {
1671 if (this.ridingEntity == null)
1672 {
1673 int var7;
1674
1675 if (this.isInsideOfMaterial(Material.water))
1676 {
1677 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5) * 100.0F);
1678
1679 if (var7 > 0)
1680 {
1681 this.addStat(StatList.distanceDoveStat, var7);
1682 this.addExhaustion(0.015F * (float)var7 * 0.01F);
1683 }
1684 }
1685 else if (this.isInWater())
1686 {
1687 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1688
1689 if (var7 > 0)
1690 {
1691 this.addStat(StatList.distanceSwumStat, var7);
1692 this.addExhaustion(0.015F * (float)var7 * 0.01F);
1693 }
1694 }
1695 else if (this.isOnLadder())
1696 {
1697 if (par3 > 0.0D)
1698 {
1699 this.addStat(StatList.distanceClimbedStat, (int)Math.round(par3 * 100.0D));
1700 }
1701 }
1702 else if (this.onGround)
1703 {
1704 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1705
1706 if (var7 > 0)
1707 {
1708 this.addStat(StatList.distanceWalkedStat, var7);
1709
1710 if (this.isSprinting())
1711 {
1712 this.addExhaustion(0.099999994F * (float)var7 * 0.01F);
1713 }
1714 else
1715 {
1716 this.addExhaustion(0.01F * (float)var7 * 0.01F);
1717 }
1718 }
1719 }
1720 else
1721 {
1722 var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par5 * par5) * 100.0F);
1723
1724 if (var7 > 25)
1725 {
1726 this.addStat(StatList.distanceFlownStat, var7);
1727 }
1728 }
1729 }
1730 }
1731
1732 /**
1733 * Adds a value to a mounted movement statistic field - by minecart, boat, or pig.
1734 */
1735 private void addMountedMovementStat(double par1, double par3, double par5)
1736 {
1737 if (this.ridingEntity != null)
1738 {
1739 int var7 = Math.round(MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5) * 100.0F);
1740
1741 if (var7 > 0)
1742 {
1743 if (this.ridingEntity instanceof EntityMinecart)
1744 {
1745 this.addStat(StatList.distanceByMinecartStat, var7);
1746
1747 if (this.startMinecartRidingCoordinate == null)
1748 {
1749 this.startMinecartRidingCoordinate = new ChunkCoordinates(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
1750 }
1751 else if ((double)this.startMinecartRidingCoordinate.getDistanceSquared(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) >= 1000000.0D)
1752 {
1753 this.addStat(AchievementList.onARail, 1);
1754 }
1755 }
1756 else if (this.ridingEntity instanceof EntityBoat)
1757 {
1758 this.addStat(StatList.distanceByBoatStat, var7);
1759 }
1760 else if (this.ridingEntity instanceof EntityPig)
1761 {
1762 this.addStat(StatList.distanceByPigStat, var7);
1763 }
1764 }
1765 }
1766 }
1767
1768 /**
1769 * Called when the mob is falling. Calculates and applies fall damage.
1770 */
1771 protected void fall(float par1)
1772 {
1773 if (!this.capabilities.allowFlying)
1774 {
1775 if (par1 >= 2.0F)
1776 {
1777 this.addStat(StatList.distanceFallenStat, (int)Math.round((double)par1 * 100.0D));
1778 }
1779
1780 super.fall(par1);
1781 }
1782 }
1783
1784 /**
1785 * This method gets called when the entity kills another one.
1786 */
1787 public void onKillEntity(EntityLiving par1EntityLiving)
1788 {
1789 if (par1EntityLiving instanceof IMob)
1790 {
1791 this.triggerAchievement(AchievementList.killEnemy);
1792 }
1793 }
1794
1795 @SideOnly(Side.CLIENT)
1796
1797 /**
1798 * Gets the Icon Index of the item currently held
1799 */
1800 public int getItemIcon(ItemStack par1ItemStack, int par2)
1801 {
1802 int var3 = super.getItemIcon(par1ItemStack, par2);
1803
1804 if (par1ItemStack.itemID == Item.fishingRod.shiftedIndex && this.fishEntity != null)
1805 {
1806 var3 = par1ItemStack.getIconIndex() + 16;
1807 }
1808 else
1809 {
1810 if (par1ItemStack.getItem().requiresMultipleRenderPasses())
1811 {
1812 return par1ItemStack.getItem().getIconFromDamageForRenderPass(par1ItemStack.getItemDamage(), par2);
1813 }
1814
1815 if (this.itemInUse != null && par1ItemStack.itemID == Item.bow.shiftedIndex)
1816 {
1817 int var4 = par1ItemStack.getMaxItemUseDuration() - this.itemInUseCount;
1818
1819 if (var4 >= 18)
1820 {
1821 return 133;
1822 }
1823
1824 if (var4 > 13)
1825 {
1826 return 117;
1827 }
1828
1829 if (var4 > 0)
1830 {
1831 return 101;
1832 }
1833 }
1834 var3 = par1ItemStack.getItem().getIconIndex(par1ItemStack, par2, this, itemInUse, itemInUseCount);
1835 }
1836
1837 return var3;
1838 }
1839
1840 public ItemStack func_82169_q(int par1)
1841 {
1842 return this.inventory.armorItemInSlot(par1);
1843 }
1844
1845 protected void func_82164_bB() {}
1846
1847 protected void func_82162_bC() {}
1848
1849 /**
1850 * This method increases the player's current amount of experience.
1851 */
1852 public void addExperience(int par1)
1853 {
1854 this.score += par1;
1855 int var2 = Integer.MAX_VALUE - this.experienceTotal;
1856
1857 if (par1 > var2)
1858 {
1859 par1 = var2;
1860 }
1861
1862 this.experience += (float)par1 / (float)this.xpBarCap();
1863
1864 for (this.experienceTotal += par1; this.experience >= 1.0F; this.experience /= (float)this.xpBarCap())
1865 {
1866 this.experience = (this.experience - 1.0F) * (float)this.xpBarCap();
1867 this.func_82242_a(1);
1868 }
1869 }
1870
1871 public void func_82242_a(int par1)
1872 {
1873 this.experienceLevel += par1;
1874
1875 if (this.experienceLevel < 0)
1876 {
1877 this.experienceLevel = 0;
1878 }
1879
1880 if (par1 > 0 && this.experienceLevel % 5 == 0 && (float)this.field_82249_h < (float)this.ticksExisted - 100.0F)
1881 {
1882 float var2 = this.experienceLevel > 30 ? 1.0F : (float)this.experienceLevel / 30.0F;
1883 this.worldObj.playSoundAtEntity(this, "random.levelup", var2 * 0.75F, 1.0F);
1884 this.field_82249_h = this.ticksExisted;
1885 }
1886 }
1887
1888 /**
1889 * This method returns the cap amount of experience that the experience bar can hold. With each level, the
1890 * experience cap on the player's experience bar is raised by 10.
1891 */
1892 public int xpBarCap()
1893 {
1894 return this.experienceLevel >= 30 ? 62 + (this.experienceLevel - 30) * 7 : (this.experienceLevel >= 15 ? 17 + (this.experienceLevel - 15) * 3 : 17);
1895 }
1896
1897 /**
1898 * increases exhaustion level by supplied amount
1899 */
1900 public void addExhaustion(float par1)
1901 {
1902 if (!this.capabilities.disableDamage)
1903 {
1904 if (!this.worldObj.isRemote)
1905 {
1906 this.foodStats.addExhaustion(par1);
1907 }
1908 }
1909 }
1910
1911 /**
1912 * Returns the player's FoodStats object.
1913 */
1914 public FoodStats getFoodStats()
1915 {
1916 return this.foodStats;
1917 }
1918
1919 public boolean canEat(boolean par1)
1920 {
1921 return (par1 || this.foodStats.needFood()) && !this.capabilities.disableDamage;
1922 }
1923
1924 /**
1925 * Checks if the player's health is not full and not zero.
1926 */
1927 public boolean shouldHeal()
1928 {
1929 return this.getHealth() > 0 && this.getHealth() < this.getMaxHealth();
1930 }
1931
1932 /**
1933 * sets the itemInUse when the use item button is clicked. Args: itemstack, int maxItemUseDuration
1934 */
1935 public void setItemInUse(ItemStack par1ItemStack, int par2)
1936 {
1937 if (par1ItemStack != this.itemInUse)
1938 {
1939 this.itemInUse = par1ItemStack;
1940 this.itemInUseCount = par2;
1941
1942 if (!this.worldObj.isRemote)
1943 {
1944 this.setEating(true);
1945 }
1946 }
1947 }
1948
1949 public boolean func_82246_f(int par1, int par2, int par3)
1950 {
1951 if (this.capabilities.allowEdit)
1952 {
1953 return true;
1954 }
1955 else
1956 {
1957 int var4 = this.worldObj.getBlockId(par1, par2, par3);
1958
1959 if (var4 > 0 && this.getCurrentEquippedItem() != null)
1960 {
1961 Block var5 = Block.blocksList[var4];
1962 ItemStack var6 = this.getCurrentEquippedItem();
1963
1964 if (var6.canHarvestBlock(var5) || var6.getStrVsBlock(var5) > 1.0F)
1965 {
1966 return true;
1967 }
1968 }
1969
1970 return false;
1971 }
1972 }
1973
1974 public boolean func_82247_a(int par1, int par2, int par3, int par4, ItemStack par5ItemStack)
1975 {
1976 return this.capabilities.allowEdit ? true : (par5ItemStack != null ? par5ItemStack.func_82835_x() : false);
1977 }
1978
1979 /**
1980 * Get the experience points the entity currently has.
1981 */
1982 protected int getExperiencePoints(EntityPlayer par1EntityPlayer)
1983 {
1984 if (this.worldObj.func_82736_K().func_82766_b("keepInventory"))
1985 {
1986 return 0;
1987 }
1988 else
1989 {
1990 int var2 = this.experienceLevel * 7;
1991 return var2 > 100 ? 100 : var2;
1992 }
1993 }
1994
1995 /**
1996 * Only use is to identify if class is an instance of player for experience dropping
1997 */
1998 protected boolean isPlayer()
1999 {
2000 return true;
2001 }
2002
2003 /**
2004 * Gets the username of the entity.
2005 */
2006 public String getEntityName()
2007 {
2008 return this.username;
2009 }
2010
2011 /**
2012 * Copies the values from the given player into this player if boolean par2 is true. Always clones Ender Chest
2013 * Inventory.
2014 */
2015 public void clonePlayer(EntityPlayer par1EntityPlayer, boolean par2)
2016 {
2017 if (par2)
2018 {
2019 this.inventory.copyInventory(par1EntityPlayer.inventory);
2020 this.health = par1EntityPlayer.health;
2021 this.foodStats = par1EntityPlayer.foodStats;
2022 this.experienceLevel = par1EntityPlayer.experienceLevel;
2023 this.experienceTotal = par1EntityPlayer.experienceTotal;
2024 this.experience = par1EntityPlayer.experience;
2025 this.score = par1EntityPlayer.score;
2026 this.field_82152_aq = par1EntityPlayer.field_82152_aq;
2027 }
2028 else if (this.worldObj.func_82736_K().func_82766_b("keepInventory"))
2029 {
2030 this.inventory.copyInventory(par1EntityPlayer.inventory);
2031 this.experienceLevel = par1EntityPlayer.experienceLevel;
2032 this.experienceTotal = par1EntityPlayer.experienceTotal;
2033 this.experience = par1EntityPlayer.experience;
2034 this.score = par1EntityPlayer.score;
2035 }
2036
2037 this.theInventoryEnderChest = par1EntityPlayer.theInventoryEnderChest;
2038 }
2039
2040 /**
2041 * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
2042 * prevent them from trampling crops
2043 */
2044 protected boolean canTriggerWalking()
2045 {
2046 return !this.capabilities.isFlying;
2047 }
2048
2049 /**
2050 * Sends the player's abilities to the server (if there is one).
2051 */
2052 public void sendPlayerAbilities() {}
2053
2054 public void sendGameTypeToPlayer(EnumGameType par1EnumGameType) {}
2055
2056 /**
2057 * Gets the name of this command sender (usually username, but possibly "Rcon")
2058 */
2059 public String getCommandSenderName()
2060 {
2061 return this.username;
2062 }
2063
2064 public StringTranslate getTranslator()
2065 {
2066 return StringTranslate.getInstance();
2067 }
2068
2069 /**
2070 * Translates and formats the given string key with the given arguments.
2071 */
2072 public String translateString(String par1Str, Object ... par2ArrayOfObj)
2073 {
2074 return this.getTranslator().translateKeyFormat(par1Str, par2ArrayOfObj);
2075 }
2076
2077 /**
2078 * Returns the InventoryEnderChest of this player.
2079 */
2080 public InventoryEnderChest getInventoryEnderChest()
2081 {
2082 return this.theInventoryEnderChest;
2083 }
2084
2085 /**
2086 * 0 = item, 1-n is armor
2087 */
2088 public ItemStack getCurrentItemOrArmor(int par1)
2089 {
2090 return par1 == 0 ? this.inventory.getCurrentItem() : this.inventory.armorInventory[par1 - 1];
2091 }
2092
2093 /**
2094 * Returns the item that this EntityLiving is holding, if any.
2095 */
2096 public ItemStack getHeldItem()
2097 {
2098 return this.inventory.getCurrentItem();
2099 }
2100
2101 public void func_70062_b(int par1, ItemStack par2ItemStack)
2102 {
2103 this.inventory.armorInventory[par1] = par2ItemStack;
2104 }
2105
2106 public ItemStack[] getLastActiveItems()
2107 {
2108 return this.inventory.armorInventory;
2109 }
2110
2111 @SideOnly(Side.CLIENT)
2112 public boolean func_82238_cc()
2113 {
2114 return this.func_82241_s(1);
2115 }
2116
2117 public void openGui(Object mod, int modGuiId, World world, int x, int y, int z)
2118 {
2119 FMLNetworkHandler.openGui(this, mod, modGuiId, world, x, y, z);
2120 }
2121 }