001 package net.minecraft.entity.player; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import net.minecraft.block.Block; 006 import net.minecraft.entity.Entity; 007 import net.minecraft.inventory.IInventory; 008 import net.minecraft.item.Item; 009 import net.minecraft.item.ItemArmor; 010 import net.minecraft.item.ItemStack; 011 import net.minecraft.nbt.NBTTagCompound; 012 import net.minecraft.nbt.NBTTagList; 013 014 public 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 342 /** 343 * removed one item of specified itemID from inventory (if it is in a stack, the stack size will reduce with 1) 344 */ 345 public boolean consumeInventoryItem(int par1) 346 { 347 int var2 = this.getInventorySlotContainItem(par1); 348 349 if (var2 < 0) 350 { 351 return false; 352 } 353 else 354 { 355 if (--this.mainInventory[var2].stackSize <= 0) 356 { 357 this.mainInventory[var2] = null; 358 } 359 360 return true; 361 } 362 } 363 364 /** 365 * Get if a specifiied item id is inside the inventory. 366 */ 367 public boolean hasItem(int par1) 368 { 369 int var2 = this.getInventorySlotContainItem(par1); 370 return var2 >= 0; 371 } 372 373 /** 374 * Adds the item stack to the inventory, returns false if it is impossible. 375 */ 376 public boolean addItemStackToInventory(ItemStack par1ItemStack) 377 { 378 int var2; 379 380 if (par1ItemStack.isItemDamaged()) 381 { 382 var2 = this.getFirstEmptyStack(); 383 384 if (var2 >= 0) 385 { 386 this.mainInventory[var2] = ItemStack.copyItemStack(par1ItemStack); 387 this.mainInventory[var2].animationsToGo = 5; 388 par1ItemStack.stackSize = 0; 389 return true; 390 } 391 else if (this.player.capabilities.isCreativeMode) 392 { 393 par1ItemStack.stackSize = 0; 394 return true; 395 } 396 else 397 { 398 return false; 399 } 400 } 401 else 402 { 403 do 404 { 405 var2 = par1ItemStack.stackSize; 406 par1ItemStack.stackSize = this.storePartialItemStack(par1ItemStack); 407 } 408 while (par1ItemStack.stackSize > 0 && par1ItemStack.stackSize < var2); 409 410 if (par1ItemStack.stackSize == var2 && this.player.capabilities.isCreativeMode) 411 { 412 par1ItemStack.stackSize = 0; 413 return true; 414 } 415 else 416 { 417 return par1ItemStack.stackSize < var2; 418 } 419 } 420 } 421 422 /** 423 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 424 * new stack. 425 */ 426 public ItemStack decrStackSize(int par1, int par2) 427 { 428 ItemStack[] var3 = this.mainInventory; 429 430 if (par1 >= this.mainInventory.length) 431 { 432 var3 = this.armorInventory; 433 par1 -= this.mainInventory.length; 434 } 435 436 if (var3[par1] != null) 437 { 438 ItemStack var4; 439 440 if (var3[par1].stackSize <= par2) 441 { 442 var4 = var3[par1]; 443 var3[par1] = null; 444 return var4; 445 } 446 else 447 { 448 var4 = var3[par1].splitStack(par2); 449 450 if (var3[par1].stackSize == 0) 451 { 452 var3[par1] = null; 453 } 454 455 return var4; 456 } 457 } 458 else 459 { 460 return null; 461 } 462 } 463 464 /** 465 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 466 * like when you close a workbench GUI. 467 */ 468 public ItemStack getStackInSlotOnClosing(int par1) 469 { 470 ItemStack[] var2 = this.mainInventory; 471 472 if (par1 >= this.mainInventory.length) 473 { 474 var2 = this.armorInventory; 475 par1 -= this.mainInventory.length; 476 } 477 478 if (var2[par1] != null) 479 { 480 ItemStack var3 = var2[par1]; 481 var2[par1] = null; 482 return var3; 483 } 484 else 485 { 486 return null; 487 } 488 } 489 490 /** 491 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 492 */ 493 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 494 { 495 ItemStack[] var3 = this.mainInventory; 496 497 if (par1 >= var3.length) 498 { 499 par1 -= var3.length; 500 var3 = this.armorInventory; 501 } 502 503 var3[par1] = par2ItemStack; 504 } 505 506 /** 507 * Gets the strength of the current item (tool) against the specified block, 1.0f if not holding anything. 508 */ 509 public float getStrVsBlock(Block par1Block) 510 { 511 float var2 = 1.0F; 512 513 if (this.mainInventory[this.currentItem] != null) 514 { 515 var2 *= this.mainInventory[this.currentItem].getStrVsBlock(par1Block); 516 } 517 518 return var2; 519 } 520 521 /** 522 * Writes the inventory out as a list of compound tags. This is where the slot indices are used (+100 for armor, +80 523 * for crafting). 524 */ 525 public NBTTagList writeToNBT(NBTTagList par1NBTTagList) 526 { 527 int var2; 528 NBTTagCompound var3; 529 530 for (var2 = 0; var2 < this.mainInventory.length; ++var2) 531 { 532 if (this.mainInventory[var2] != null) 533 { 534 var3 = new NBTTagCompound(); 535 var3.setByte("Slot", (byte)var2); 536 this.mainInventory[var2].writeToNBT(var3); 537 par1NBTTagList.appendTag(var3); 538 } 539 } 540 541 for (var2 = 0; var2 < this.armorInventory.length; ++var2) 542 { 543 if (this.armorInventory[var2] != null) 544 { 545 var3 = new NBTTagCompound(); 546 var3.setByte("Slot", (byte)(var2 + 100)); 547 this.armorInventory[var2].writeToNBT(var3); 548 par1NBTTagList.appendTag(var3); 549 } 550 } 551 552 return par1NBTTagList; 553 } 554 555 /** 556 * Reads from the given tag list and fills the slots in the inventory with the correct items. 557 */ 558 public void readFromNBT(NBTTagList par1NBTTagList) 559 { 560 this.mainInventory = new ItemStack[36]; 561 this.armorInventory = new ItemStack[4]; 562 563 for (int var2 = 0; var2 < par1NBTTagList.tagCount(); ++var2) 564 { 565 NBTTagCompound var3 = (NBTTagCompound)par1NBTTagList.tagAt(var2); 566 int var4 = var3.getByte("Slot") & 255; 567 ItemStack var5 = ItemStack.loadItemStackFromNBT(var3); 568 569 if (var5 != null) 570 { 571 if (var4 >= 0 && var4 < this.mainInventory.length) 572 { 573 this.mainInventory[var4] = var5; 574 } 575 576 if (var4 >= 100 && var4 < this.armorInventory.length + 100) 577 { 578 this.armorInventory[var4 - 100] = var5; 579 } 580 } 581 } 582 } 583 584 /** 585 * Returns the number of slots in the inventory. 586 */ 587 public int getSizeInventory() 588 { 589 return this.mainInventory.length + 4; 590 } 591 592 /** 593 * Returns the stack in slot i 594 */ 595 public ItemStack getStackInSlot(int par1) 596 { 597 ItemStack[] var2 = this.mainInventory; 598 599 if (par1 >= var2.length) 600 { 601 par1 -= var2.length; 602 var2 = this.armorInventory; 603 } 604 605 return var2[par1]; 606 } 607 608 /** 609 * Returns the name of the inventory. 610 */ 611 public String getInvName() 612 { 613 return "container.inventory"; 614 } 615 616 /** 617 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 618 * this more of a set than a get?* 619 */ 620 public int getInventoryStackLimit() 621 { 622 return 64; 623 } 624 625 /** 626 * Return damage vs an entity done by the current held weapon, or 1 if nothing is held 627 */ 628 public int getDamageVsEntity(Entity par1Entity) 629 { 630 ItemStack var2 = this.getStackInSlot(this.currentItem); 631 return var2 != null ? var2.getDamageVsEntity(par1Entity) : 1; 632 } 633 634 /** 635 * Returns whether the current item (tool) can harvest from the specified block (actually get a result). 636 */ 637 public boolean canHarvestBlock(Block par1Block) 638 { 639 if (par1Block.blockMaterial.isToolNotRequired()) 640 { 641 return true; 642 } 643 else 644 { 645 ItemStack var2 = this.getStackInSlot(this.currentItem); 646 return var2 != null ? var2.canHarvestBlock(par1Block) : false; 647 } 648 } 649 650 /** 651 * returns a player armor item (as itemstack) contained in specified armor slot. 652 */ 653 public ItemStack armorItemInSlot(int par1) 654 { 655 return this.armorInventory[par1]; 656 } 657 658 /** 659 * Based on the damage values and maximum damage values of each armor item, returns the current armor value. 660 */ 661 public int getTotalArmorValue() 662 { 663 int var1 = 0; 664 665 for (int var2 = 0; var2 < this.armorInventory.length; ++var2) 666 { 667 if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor) 668 { 669 int var3 = ((ItemArmor)this.armorInventory[var2].getItem()).damageReduceAmount; 670 var1 += var3; 671 } 672 } 673 674 return var1; 675 } 676 677 /** 678 * Damages armor in each slot by the specified amount. 679 */ 680 public void damageArmor(int par1) 681 { 682 par1 /= 4; 683 684 if (par1 < 1) 685 { 686 par1 = 1; 687 } 688 689 for (int var2 = 0; var2 < this.armorInventory.length; ++var2) 690 { 691 if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor) 692 { 693 this.armorInventory[var2].damageItem(par1, this.player); 694 695 if (this.armorInventory[var2].stackSize == 0) 696 { 697 this.armorInventory[var2] = null; 698 } 699 } 700 } 701 } 702 703 /** 704 * Drop all armor and main inventory items. 705 */ 706 public void dropAllItems() 707 { 708 int var1; 709 710 for (var1 = 0; var1 < this.mainInventory.length; ++var1) 711 { 712 if (this.mainInventory[var1] != null) 713 { 714 this.player.dropPlayerItemWithRandomChoice(this.mainInventory[var1], true); 715 this.mainInventory[var1] = null; 716 } 717 } 718 719 for (var1 = 0; var1 < this.armorInventory.length; ++var1) 720 { 721 if (this.armorInventory[var1] != null) 722 { 723 this.player.dropPlayerItemWithRandomChoice(this.armorInventory[var1], true); 724 this.armorInventory[var1] = null; 725 } 726 } 727 } 728 729 /** 730 * Called when an the contents of an Inventory change, usually 731 */ 732 public void onInventoryChanged() 733 { 734 this.inventoryChanged = true; 735 } 736 737 public void setItemStack(ItemStack par1ItemStack) 738 { 739 this.itemStack = par1ItemStack; 740 } 741 742 public ItemStack getItemStack() 743 { 744 return this.itemStack; 745 } 746 747 /** 748 * Do not make give this method the name canInteractWith because it clashes with Container 749 */ 750 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 751 { 752 return this.player.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this.player) <= 64.0D; 753 } 754 755 /** 756 * Returns true if the specified ItemStack exists in the inventory. 757 */ 758 public boolean hasItemStack(ItemStack par1ItemStack) 759 { 760 int var2; 761 762 for (var2 = 0; var2 < this.armorInventory.length; ++var2) 763 { 764 if (this.armorInventory[var2] != null && this.armorInventory[var2].isItemEqual(par1ItemStack)) 765 { 766 return true; 767 } 768 } 769 770 for (var2 = 0; var2 < this.mainInventory.length; ++var2) 771 { 772 if (this.mainInventory[var2] != null && this.mainInventory[var2].isItemEqual(par1ItemStack)) 773 { 774 return true; 775 } 776 } 777 778 return false; 779 } 780 781 public void openChest() {} 782 783 public void closeChest() {} 784 785 /** 786 * Copy the ItemStack contents from another InventoryPlayer instance 787 */ 788 public void copyInventory(InventoryPlayer par1InventoryPlayer) 789 { 790 int var2; 791 792 for (var2 = 0; var2 < this.mainInventory.length; ++var2) 793 { 794 this.mainInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.mainInventory[var2]); 795 } 796 797 for (var2 = 0; var2 < this.armorInventory.length; ++var2) 798 { 799 this.armorInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.armorInventory[var2]); 800 } 801 802 this.currentItem = par1InventoryPlayer.currentItem; 803 } 804 }