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