001package net.minecraft.entity.player; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import net.minecraft.block.Block; 006import net.minecraft.crash.CrashReport; 007import net.minecraft.crash.CrashReportCategory; 008import net.minecraft.entity.Entity; 009import net.minecraft.inventory.IInventory; 010import net.minecraft.item.Item; 011import net.minecraft.item.ItemArmor; 012import net.minecraft.item.ItemStack; 013import net.minecraft.nbt.NBTTagCompound; 014import net.minecraft.nbt.NBTTagList; 015import net.minecraft.util.ReportedException; 016 017public class InventoryPlayer implements IInventory 018{ 019 /** 020 * An array of 36 item stacks indicating the main player inventory (including the visible bar). 021 */ 022 public ItemStack[] mainInventory = new ItemStack[36]; 023 024 /** An array of 4 item stacks containing the currently worn armor pieces. */ 025 public ItemStack[] armorInventory = new ItemStack[4]; 026 027 /** The index of the currently held item (0-8). */ 028 public int currentItem = 0; 029 @SideOnly(Side.CLIENT) 030 031 /** The current ItemStack. */ 032 private ItemStack currentItemStack; 033 034 /** The player whose inventory this is. */ 035 public EntityPlayer player; 036 private ItemStack itemStack; 037 038 /** 039 * Set true whenever the inventory changes. Nothing sets it false so you will have to write your own code to check 040 * it and reset the value. 041 */ 042 public boolean inventoryChanged = false; 043 044 public InventoryPlayer(EntityPlayer par1EntityPlayer) 045 { 046 this.player = par1EntityPlayer; 047 } 048 049 /** 050 * Returns the item stack currently held by the player. 051 */ 052 public ItemStack getCurrentItem() 053 { 054 return this.currentItem < 9 && this.currentItem >= 0 ? this.mainInventory[this.currentItem] : null; 055 } 056 057 /** 058 * Get the size of the player hotbar inventory 059 */ 060 public static int getHotbarSize() 061 { 062 return 9; 063 } 064 065 /** 066 * Returns a slot index in main inventory containing a specific itemID 067 */ 068 private int getInventorySlotContainItem(int par1) 069 { 070 for (int j = 0; j < this.mainInventory.length; ++j) 071 { 072 if (this.mainInventory[j] != null && this.mainInventory[j].itemID == par1) 073 { 074 return j; 075 } 076 } 077 078 return -1; 079 } 080 081 @SideOnly(Side.CLIENT) 082 private int getInventorySlotContainItemAndDamage(int par1, int par2) 083 { 084 for (int k = 0; k < this.mainInventory.length; ++k) 085 { 086 if (this.mainInventory[k] != null && this.mainInventory[k].itemID == par1 && this.mainInventory[k].getItemDamage() == par2) 087 { 088 return k; 089 } 090 } 091 092 return -1; 093 } 094 095 /** 096 * stores an itemstack in the users inventory 097 */ 098 private int storeItemStack(ItemStack par1ItemStack) 099 { 100 for (int i = 0; i < this.mainInventory.length; ++i) 101 { 102 if (this.mainInventory[i] != null && this.mainInventory[i].itemID == par1ItemStack.itemID && this.mainInventory[i].isStackable() && this.mainInventory[i].stackSize < this.mainInventory[i].getMaxStackSize() && this.mainInventory[i].stackSize < this.getInventoryStackLimit() && (!this.mainInventory[i].getHasSubtypes() || this.mainInventory[i].getItemDamage() == par1ItemStack.getItemDamage()) && ItemStack.areItemStackTagsEqual(this.mainInventory[i], par1ItemStack)) 103 { 104 return i; 105 } 106 } 107 108 return -1; 109 } 110 111 /** 112 * Returns the first item stack that is empty. 113 */ 114 public int getFirstEmptyStack() 115 { 116 for (int i = 0; i < this.mainInventory.length; ++i) 117 { 118 if (this.mainInventory[i] == null) 119 { 120 return i; 121 } 122 } 123 124 return -1; 125 } 126 127 @SideOnly(Side.CLIENT) 128 129 /** 130 * Sets a specific itemID as the current item being held (only if it exists on the hotbar) 131 */ 132 public void setCurrentItem(int par1, int par2, boolean par3, boolean par4) 133 { 134 boolean flag2 = true; 135 this.currentItemStack = this.getCurrentItem(); 136 int k; 137 138 if (par3) 139 { 140 k = this.getInventorySlotContainItemAndDamage(par1, par2); 141 } 142 else 143 { 144 k = this.getInventorySlotContainItem(par1); 145 } 146 147 if (k >= 0 && k < 9) 148 { 149 this.currentItem = k; 150 } 151 else 152 { 153 if (par4 && par1 > 0) 154 { 155 int l = this.getFirstEmptyStack(); 156 157 if (l >= 0 && l < 9) 158 { 159 this.currentItem = l; 160 } 161 162 this.func_70439_a(Item.itemsList[par1], par2); 163 } 164 } 165 } 166 167 @SideOnly(Side.CLIENT) 168 169 /** 170 * Switch the current item to the next one or the previous one 171 */ 172 public void changeCurrentItem(int par1) 173 { 174 if (par1 > 0) 175 { 176 par1 = 1; 177 } 178 179 if (par1 < 0) 180 { 181 par1 = -1; 182 } 183 184 for (this.currentItem -= par1; this.currentItem < 0; this.currentItem += 9) 185 { 186 ; 187 } 188 189 while (this.currentItem >= 9) 190 { 191 this.currentItem -= 9; 192 } 193 } 194 195 /** 196 * Clear this player's inventory, using the specified ID and metadata as filters or -1 for no filter. 197 */ 198 public int clearInventory(int par1, int par2) 199 { 200 int k = 0; 201 int l; 202 ItemStack itemstack; 203 204 for (l = 0; l < this.mainInventory.length; ++l) 205 { 206 itemstack = this.mainInventory[l]; 207 208 if (itemstack != null && (par1 <= -1 || itemstack.itemID == par1) && (par2 <= -1 || itemstack.getItemDamage() == par2)) 209 { 210 k += itemstack.stackSize; 211 this.mainInventory[l] = null; 212 } 213 } 214 215 for (l = 0; l < this.armorInventory.length; ++l) 216 { 217 itemstack = this.armorInventory[l]; 218 219 if (itemstack != null && (par1 <= -1 || itemstack.itemID == par1) && (par2 <= -1 || itemstack.getItemDamage() == par2)) 220 { 221 k += itemstack.stackSize; 222 this.armorInventory[l] = null; 223 } 224 } 225 226 return k; 227 } 228 229 @SideOnly(Side.CLIENT) 230 public void func_70439_a(Item par1Item, int par2) 231 { 232 if (par1Item != null) 233 { 234 int j = this.getInventorySlotContainItemAndDamage(par1Item.itemID, par2); 235 236 if (j >= 0) 237 { 238 this.mainInventory[j] = this.mainInventory[this.currentItem]; 239 } 240 241 if (this.currentItemStack != null && this.currentItemStack.isItemEnchantable() && this.getInventorySlotContainItemAndDamage(this.currentItemStack.itemID, this.currentItemStack.getItemDamageForDisplay()) == this.currentItem) 242 { 243 return; 244 } 245 246 this.mainInventory[this.currentItem] = new ItemStack(Item.itemsList[par1Item.itemID], 1, par2); 247 } 248 } 249 250 /** 251 * This function stores as many items of an ItemStack as possible in a matching slot and returns the quantity of 252 * left over items. 253 */ 254 private int storePartialItemStack(ItemStack par1ItemStack) 255 { 256 int i = par1ItemStack.itemID; 257 int j = par1ItemStack.stackSize; 258 int k; 259 260 if (par1ItemStack.getMaxStackSize() == 1) 261 { 262 k = this.getFirstEmptyStack(); 263 264 if (k < 0) 265 { 266 return j; 267 } 268 else 269 { 270 if (this.mainInventory[k] == null) 271 { 272 this.mainInventory[k] = ItemStack.copyItemStack(par1ItemStack); 273 } 274 275 return 0; 276 } 277 } 278 else 279 { 280 k = this.storeItemStack(par1ItemStack); 281 282 if (k < 0) 283 { 284 k = this.getFirstEmptyStack(); 285 } 286 287 if (k < 0) 288 { 289 return j; 290 } 291 else 292 { 293 if (this.mainInventory[k] == null) 294 { 295 this.mainInventory[k] = new ItemStack(i, 0, par1ItemStack.getItemDamage()); 296 297 if (par1ItemStack.hasTagCompound()) 298 { 299 this.mainInventory[k].setTagCompound((NBTTagCompound)par1ItemStack.getTagCompound().copy()); 300 } 301 } 302 303 int l = j; 304 305 if (j > this.mainInventory[k].getMaxStackSize() - this.mainInventory[k].stackSize) 306 { 307 l = this.mainInventory[k].getMaxStackSize() - this.mainInventory[k].stackSize; 308 } 309 310 if (l > this.getInventoryStackLimit() - this.mainInventory[k].stackSize) 311 { 312 l = this.getInventoryStackLimit() - this.mainInventory[k].stackSize; 313 } 314 315 if (l == 0) 316 { 317 return j; 318 } 319 else 320 { 321 j -= l; 322 this.mainInventory[k].stackSize += l; 323 this.mainInventory[k].animationsToGo = 5; 324 return j; 325 } 326 } 327 } 328 } 329 330 /** 331 * Decrement the number of animations remaining. Only called on client side. This is used to handle the animation of 332 * receiving a block. 333 */ 334 public void decrementAnimations() 335 { 336 for (int i = 0; i < this.mainInventory.length; ++i) 337 { 338 if (this.mainInventory[i] != null) 339 { 340 this.mainInventory[i].updateAnimation(this.player.worldObj, this.player, i, this.currentItem == i); 341 } 342 } 343 344 for (int i = 0; i < this.armorInventory.length; i++) 345 { 346 if (this.armorInventory[i] != null) 347 { 348 this.armorInventory[i].getItem().onArmorTickUpdate(this.player.worldObj, this.player, this.armorInventory[i]); 349 } 350 } 351 } 352 353 /** 354 * removed one item of specified itemID from inventory (if it is in a stack, the stack size will reduce with 1) 355 */ 356 public boolean consumeInventoryItem(int par1) 357 { 358 int j = this.getInventorySlotContainItem(par1); 359 360 if (j < 0) 361 { 362 return false; 363 } 364 else 365 { 366 if (--this.mainInventory[j].stackSize <= 0) 367 { 368 this.mainInventory[j] = null; 369 } 370 371 return true; 372 } 373 } 374 375 /** 376 * Get if a specifiied item id is inside the inventory. 377 */ 378 public boolean hasItem(int par1) 379 { 380 int j = this.getInventorySlotContainItem(par1); 381 return j >= 0; 382 } 383 384 /** 385 * Adds the item stack to the inventory, returns false if it is impossible. 386 */ 387 public boolean addItemStackToInventory(ItemStack par1ItemStack) 388 { 389 if (par1ItemStack == null) 390 { 391 return false; 392 } 393 else 394 { 395 try 396 { 397 int i; 398 399 if (par1ItemStack.isItemDamaged()) 400 { 401 i = this.getFirstEmptyStack(); 402 403 if (i >= 0) 404 { 405 this.mainInventory[i] = ItemStack.copyItemStack(par1ItemStack); 406 this.mainInventory[i].animationsToGo = 5; 407 par1ItemStack.stackSize = 0; 408 return true; 409 } 410 else if (this.player.capabilities.isCreativeMode) 411 { 412 par1ItemStack.stackSize = 0; 413 return true; 414 } 415 else 416 { 417 return false; 418 } 419 } 420 else 421 { 422 do 423 { 424 i = par1ItemStack.stackSize; 425 par1ItemStack.stackSize = this.storePartialItemStack(par1ItemStack); 426 } 427 while (par1ItemStack.stackSize > 0 && par1ItemStack.stackSize < i); 428 429 if (par1ItemStack.stackSize == i && this.player.capabilities.isCreativeMode) 430 { 431 par1ItemStack.stackSize = 0; 432 return true; 433 } 434 else 435 { 436 return par1ItemStack.stackSize < i; 437 } 438 } 439 } 440 catch (Throwable throwable) 441 { 442 CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Adding item to inventory"); 443 CrashReportCategory crashreportcategory = crashreport.makeCategory("Item being added"); 444 crashreportcategory.addCrashSection("Item ID", Integer.valueOf(par1ItemStack.itemID)); 445 crashreportcategory.addCrashSection("Item data", Integer.valueOf(par1ItemStack.getItemDamage())); 446 crashreportcategory.addCrashSectionCallable("Item name", new CallableItemName(this, par1ItemStack)); 447 throw new ReportedException(crashreport); 448 } 449 } 450 } 451 452 /** 453 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 454 * new stack. 455 */ 456 public ItemStack decrStackSize(int par1, int par2) 457 { 458 ItemStack[] aitemstack = this.mainInventory; 459 460 if (par1 >= this.mainInventory.length) 461 { 462 aitemstack = this.armorInventory; 463 par1 -= this.mainInventory.length; 464 } 465 466 if (aitemstack[par1] != null) 467 { 468 ItemStack itemstack; 469 470 if (aitemstack[par1].stackSize <= par2) 471 { 472 itemstack = aitemstack[par1]; 473 aitemstack[par1] = null; 474 return itemstack; 475 } 476 else 477 { 478 itemstack = aitemstack[par1].splitStack(par2); 479 480 if (aitemstack[par1].stackSize == 0) 481 { 482 aitemstack[par1] = null; 483 } 484 485 return itemstack; 486 } 487 } 488 else 489 { 490 return null; 491 } 492 } 493 494 /** 495 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 496 * like when you close a workbench GUI. 497 */ 498 public ItemStack getStackInSlotOnClosing(int par1) 499 { 500 ItemStack[] aitemstack = this.mainInventory; 501 502 if (par1 >= this.mainInventory.length) 503 { 504 aitemstack = this.armorInventory; 505 par1 -= this.mainInventory.length; 506 } 507 508 if (aitemstack[par1] != null) 509 { 510 ItemStack itemstack = aitemstack[par1]; 511 aitemstack[par1] = null; 512 return itemstack; 513 } 514 else 515 { 516 return null; 517 } 518 } 519 520 /** 521 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 522 */ 523 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 524 { 525 ItemStack[] aitemstack = this.mainInventory; 526 527 if (par1 >= aitemstack.length) 528 { 529 par1 -= aitemstack.length; 530 aitemstack = this.armorInventory; 531 } 532 533 aitemstack[par1] = par2ItemStack; 534 } 535 536 /** 537 * Gets the strength of the current item (tool) against the specified block, 1.0f if not holding anything. 538 */ 539 public float getStrVsBlock(Block par1Block) 540 { 541 float f = 1.0F; 542 543 if (this.mainInventory[this.currentItem] != null) 544 { 545 f *= this.mainInventory[this.currentItem].getStrVsBlock(par1Block); 546 } 547 548 return f; 549 } 550 551 /** 552 * Writes the inventory out as a list of compound tags. This is where the slot indices are used (+100 for armor, +80 553 * for crafting). 554 */ 555 public NBTTagList writeToNBT(NBTTagList par1NBTTagList) 556 { 557 int i; 558 NBTTagCompound nbttagcompound; 559 560 for (i = 0; i < this.mainInventory.length; ++i) 561 { 562 if (this.mainInventory[i] != null) 563 { 564 nbttagcompound = new NBTTagCompound(); 565 nbttagcompound.setByte("Slot", (byte)i); 566 this.mainInventory[i].writeToNBT(nbttagcompound); 567 par1NBTTagList.appendTag(nbttagcompound); 568 } 569 } 570 571 for (i = 0; i < this.armorInventory.length; ++i) 572 { 573 if (this.armorInventory[i] != null) 574 { 575 nbttagcompound = new NBTTagCompound(); 576 nbttagcompound.setByte("Slot", (byte)(i + 100)); 577 this.armorInventory[i].writeToNBT(nbttagcompound); 578 par1NBTTagList.appendTag(nbttagcompound); 579 } 580 } 581 582 return par1NBTTagList; 583 } 584 585 /** 586 * Reads from the given tag list and fills the slots in the inventory with the correct items. 587 */ 588 public void readFromNBT(NBTTagList par1NBTTagList) 589 { 590 this.mainInventory = new ItemStack[36]; 591 this.armorInventory = new ItemStack[4]; 592 593 for (int i = 0; i < par1NBTTagList.tagCount(); ++i) 594 { 595 NBTTagCompound nbttagcompound = (NBTTagCompound)par1NBTTagList.tagAt(i); 596 int j = nbttagcompound.getByte("Slot") & 255; 597 ItemStack itemstack = ItemStack.loadItemStackFromNBT(nbttagcompound); 598 599 if (itemstack != null) 600 { 601 if (j >= 0 && j < this.mainInventory.length) 602 { 603 this.mainInventory[j] = itemstack; 604 } 605 606 if (j >= 100 && j < this.armorInventory.length + 100) 607 { 608 this.armorInventory[j - 100] = itemstack; 609 } 610 } 611 } 612 } 613 614 /** 615 * Returns the number of slots in the inventory. 616 */ 617 public int getSizeInventory() 618 { 619 return this.mainInventory.length + 4; 620 } 621 622 /** 623 * Returns the stack in slot i 624 */ 625 public ItemStack getStackInSlot(int par1) 626 { 627 ItemStack[] aitemstack = this.mainInventory; 628 629 if (par1 >= aitemstack.length) 630 { 631 par1 -= aitemstack.length; 632 aitemstack = this.armorInventory; 633 } 634 635 return aitemstack[par1]; 636 } 637 638 /** 639 * Returns the name of the inventory. 640 */ 641 public String getInvName() 642 { 643 return "container.inventory"; 644 } 645 646 /** 647 * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's 648 * language. Otherwise it will be used directly. 649 */ 650 public boolean isInvNameLocalized() 651 { 652 return false; 653 } 654 655 /** 656 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 657 * this more of a set than a get?* 658 */ 659 public int getInventoryStackLimit() 660 { 661 return 64; 662 } 663 664 /** 665 * Return damage vs an entity done by the current held weapon, or 1 if nothing is held 666 */ 667 public int getDamageVsEntity(Entity par1Entity) 668 { 669 ItemStack itemstack = this.getStackInSlot(this.currentItem); 670 return itemstack != null ? itemstack.getDamageVsEntity(par1Entity) : 1; 671 } 672 673 /** 674 * Returns whether the current item (tool) can harvest from the specified block (actually get a result). 675 */ 676 public boolean canHarvestBlock(Block par1Block) 677 { 678 if (par1Block.blockMaterial.isToolNotRequired()) 679 { 680 return true; 681 } 682 else 683 { 684 ItemStack itemstack = this.getStackInSlot(this.currentItem); 685 return itemstack != null ? itemstack.canHarvestBlock(par1Block) : false; 686 } 687 } 688 689 /** 690 * returns a player armor item (as itemstack) contained in specified armor slot. 691 */ 692 public ItemStack armorItemInSlot(int par1) 693 { 694 return this.armorInventory[par1]; 695 } 696 697 /** 698 * Based on the damage values and maximum damage values of each armor item, returns the current armor value. 699 */ 700 public int getTotalArmorValue() 701 { 702 int i = 0; 703 704 for (int j = 0; j < this.armorInventory.length; ++j) 705 { 706 if (this.armorInventory[j] != null && this.armorInventory[j].getItem() instanceof ItemArmor) 707 { 708 int k = ((ItemArmor)this.armorInventory[j].getItem()).damageReduceAmount; 709 i += k; 710 } 711 } 712 713 return i; 714 } 715 716 /** 717 * Damages armor in each slot by the specified amount. 718 */ 719 public void damageArmor(int par1) 720 { 721 par1 /= 4; 722 723 if (par1 < 1) 724 { 725 par1 = 1; 726 } 727 728 for (int j = 0; j < this.armorInventory.length; ++j) 729 { 730 if (this.armorInventory[j] != null && this.armorInventory[j].getItem() instanceof ItemArmor) 731 { 732 this.armorInventory[j].damageItem(par1, this.player); 733 734 if (this.armorInventory[j].stackSize == 0) 735 { 736 this.armorInventory[j] = null; 737 } 738 } 739 } 740 } 741 742 /** 743 * Drop all armor and main inventory items. 744 */ 745 public void dropAllItems() 746 { 747 int i; 748 749 for (i = 0; i < this.mainInventory.length; ++i) 750 { 751 if (this.mainInventory[i] != null) 752 { 753 this.player.dropPlayerItemWithRandomChoice(this.mainInventory[i], true); 754 this.mainInventory[i] = null; 755 } 756 } 757 758 for (i = 0; i < this.armorInventory.length; ++i) 759 { 760 if (this.armorInventory[i] != null) 761 { 762 this.player.dropPlayerItemWithRandomChoice(this.armorInventory[i], true); 763 this.armorInventory[i] = null; 764 } 765 } 766 } 767 768 /** 769 * Called when an the contents of an Inventory change, usually 770 */ 771 public void onInventoryChanged() 772 { 773 this.inventoryChanged = true; 774 } 775 776 public void setItemStack(ItemStack par1ItemStack) 777 { 778 this.itemStack = par1ItemStack; 779 } 780 781 public ItemStack getItemStack() 782 { 783 return this.itemStack; 784 } 785 786 /** 787 * Do not make give this method the name canInteractWith because it clashes with Container 788 */ 789 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 790 { 791 return this.player.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this.player) <= 64.0D; 792 } 793 794 /** 795 * Returns true if the specified ItemStack exists in the inventory. 796 */ 797 public boolean hasItemStack(ItemStack par1ItemStack) 798 { 799 int i; 800 801 for (i = 0; i < this.armorInventory.length; ++i) 802 { 803 if (this.armorInventory[i] != null && this.armorInventory[i].isItemEqual(par1ItemStack)) 804 { 805 return true; 806 } 807 } 808 809 for (i = 0; i < this.mainInventory.length; ++i) 810 { 811 if (this.mainInventory[i] != null && this.mainInventory[i].isItemEqual(par1ItemStack)) 812 { 813 return true; 814 } 815 } 816 817 return false; 818 } 819 820 public void openChest() {} 821 822 public void closeChest() {} 823 824 /** 825 * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. 826 */ 827 public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack) 828 { 829 return true; 830 } 831 832 /** 833 * Copy the ItemStack contents from another InventoryPlayer instance 834 */ 835 public void copyInventory(InventoryPlayer par1InventoryPlayer) 836 { 837 int i; 838 839 for (i = 0; i < this.mainInventory.length; ++i) 840 { 841 this.mainInventory[i] = ItemStack.copyItemStack(par1InventoryPlayer.mainInventory[i]); 842 } 843 844 for (i = 0; i < this.armorInventory.length; ++i) 845 { 846 this.armorInventory[i] = ItemStack.copyItemStack(par1InventoryPlayer.armorInventory[i]); 847 } 848 849 this.currentItem = par1InventoryPlayer.currentItem; 850 } 851}