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