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