001package net.minecraft.item; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.ArrayList; 006import java.util.List; 007import java.util.Random; 008import net.minecraft.block.Block; 009import net.minecraft.enchantment.Enchantment; 010import net.minecraft.enchantment.EnchantmentDurability; 011import net.minecraft.enchantment.EnchantmentHelper; 012import net.minecraft.entity.Entity; 013import net.minecraft.entity.EntityLiving; 014import net.minecraft.entity.item.EntityItemFrame; 015import net.minecraft.entity.player.EntityPlayer; 016import net.minecraft.nbt.NBTBase; 017import net.minecraft.nbt.NBTTagCompound; 018import net.minecraft.nbt.NBTTagList; 019import net.minecraft.nbt.NBTTagString; 020import net.minecraft.stats.StatList; 021import net.minecraft.util.EnumChatFormatting; 022import net.minecraft.util.Icon; 023import net.minecraft.util.StatCollector; 024import net.minecraft.world.World; 025 026public final class ItemStack 027{ 028 /** Size of the stack. */ 029 public int stackSize; 030 031 /** 032 * Number of animation frames to go when receiving an item (by walking into it, for example). 033 */ 034 public int animationsToGo; 035 036 /** ID of the item. */ 037 public int itemID; 038 039 /** 040 * A NBTTagMap containing data about an ItemStack. Can only be used for non stackable items 041 */ 042 public NBTTagCompound stackTagCompound; 043 044 /** Damage dealt to the item or number of use. Raise when using items. */ 045 private int itemDamage; 046 047 /** Item frame this stack is on, or null if not on an item frame. */ 048 private EntityItemFrame itemFrame; 049 050 public ItemStack(Block par1Block) 051 { 052 this(par1Block, 1); 053 } 054 055 public ItemStack(Block par1Block, int par2) 056 { 057 this(par1Block.blockID, par2, 0); 058 } 059 060 public ItemStack(Block par1Block, int par2, int par3) 061 { 062 this(par1Block.blockID, par2, par3); 063 } 064 065 public ItemStack(Item par1Item) 066 { 067 this(par1Item.itemID, 1, 0); 068 } 069 070 public ItemStack(Item par1Item, int par2) 071 { 072 this(par1Item.itemID, par2, 0); 073 } 074 075 public ItemStack(Item par1Item, int par2, int par3) 076 { 077 this(par1Item.itemID, par2, par3); 078 } 079 080 public ItemStack(int par1, int par2, int par3) 081 { 082 this.stackSize = 0; 083 this.itemFrame = null; 084 this.itemID = par1; 085 this.stackSize = par2; 086 this.itemDamage = par3; 087 088 if (this.itemDamage < 0) 089 { 090 this.itemDamage = 0; 091 } 092 } 093 094 public static ItemStack loadItemStackFromNBT(NBTTagCompound par0NBTTagCompound) 095 { 096 ItemStack itemstack = new ItemStack(); 097 itemstack.readFromNBT(par0NBTTagCompound); 098 return itemstack.getItem() != null ? itemstack : null; 099 } 100 101 private ItemStack() 102 { 103 this.stackSize = 0; 104 this.itemFrame = null; 105 } 106 107 /** 108 * Remove the argument from the stack size. Return a new stack object with argument size. 109 */ 110 public ItemStack splitStack(int par1) 111 { 112 ItemStack itemstack = new ItemStack(this.itemID, par1, this.itemDamage); 113 114 if (this.stackTagCompound != null) 115 { 116 itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy(); 117 } 118 119 this.stackSize -= par1; 120 return itemstack; 121 } 122 123 /** 124 * Returns the object corresponding to the stack. 125 */ 126 public Item getItem() 127 { 128 return Item.itemsList[this.itemID]; 129 } 130 131 @SideOnly(Side.CLIENT) 132 133 /** 134 * Returns the icon index of the current stack. 135 */ 136 public Icon getIconIndex() 137 { 138 return this.getItem().getIconIndex(this); 139 } 140 141 @SideOnly(Side.CLIENT) 142 public int getItemSpriteNumber() 143 { 144 return this.getItem().getSpriteNumber(); 145 } 146 147 public boolean tryPlaceItemIntoWorld(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5, int par6, float par7, float par8, float par9) 148 { 149 boolean flag = this.getItem().onItemUse(this, par1EntityPlayer, par2World, par3, par4, par5, par6, par7, par8, par9); 150 151 if (flag) 152 { 153 par1EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 154 } 155 156 return flag; 157 } 158 159 /** 160 * Returns the strength of the stack against a given block. 161 */ 162 public float getStrVsBlock(Block par1Block) 163 { 164 return this.getItem().getStrVsBlock(this, par1Block); 165 } 166 167 /** 168 * Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position 169 * where this item is. Args: world, player 170 */ 171 public ItemStack useItemRightClick(World par1World, EntityPlayer par2EntityPlayer) 172 { 173 return this.getItem().onItemRightClick(this, par1World, par2EntityPlayer); 174 } 175 176 public ItemStack onFoodEaten(World par1World, EntityPlayer par2EntityPlayer) 177 { 178 return this.getItem().onEaten(this, par1World, par2EntityPlayer); 179 } 180 181 /** 182 * Write the stack fields to a NBT object. Return the new NBT object. 183 */ 184 public NBTTagCompound writeToNBT(NBTTagCompound par1NBTTagCompound) 185 { 186 par1NBTTagCompound.setShort("id", (short)this.itemID); 187 par1NBTTagCompound.setByte("Count", (byte)this.stackSize); 188 par1NBTTagCompound.setShort("Damage", (short)this.itemDamage); 189 190 if (this.stackTagCompound != null) 191 { 192 par1NBTTagCompound.setTag("tag", this.stackTagCompound); 193 } 194 195 return par1NBTTagCompound; 196 } 197 198 /** 199 * Read the stack fields from a NBT object. 200 */ 201 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 202 { 203 this.itemID = par1NBTTagCompound.getShort("id"); 204 this.stackSize = par1NBTTagCompound.getByte("Count"); 205 this.itemDamage = par1NBTTagCompound.getShort("Damage"); 206 207 if (this.itemDamage < 0) 208 { 209 this.itemDamage = 0; 210 } 211 212 if (par1NBTTagCompound.hasKey("tag")) 213 { 214 this.stackTagCompound = par1NBTTagCompound.getCompoundTag("tag"); 215 } 216 } 217 218 /** 219 * Returns maximum size of the stack. 220 */ 221 public int getMaxStackSize() 222 { 223 return this.getItem().getItemStackLimit(); 224 } 225 226 /** 227 * Returns true if the ItemStack can hold 2 or more units of the item. 228 */ 229 public boolean isStackable() 230 { 231 return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged()); 232 } 233 234 /** 235 * true if this itemStack is damageable 236 */ 237 public boolean isItemStackDamageable() 238 { 239 return Item.itemsList[this.itemID].getMaxDamage() > 0; 240 } 241 242 public boolean getHasSubtypes() 243 { 244 return Item.itemsList[this.itemID].getHasSubtypes(); 245 } 246 247 /** 248 * returns true when a damageable item is damaged 249 */ 250 public boolean isItemDamaged() 251 { 252 return this.isItemStackDamageable() && this.itemDamage > 0; 253 } 254 255 /** 256 * gets the damage of an itemstack, for displaying purposes 257 */ 258 public int getItemDamageForDisplay() 259 { 260 return this.itemDamage; 261 } 262 263 /** 264 * gets the damage of an itemstack 265 */ 266 public int getItemDamage() 267 { 268 return this.itemDamage; 269 } 270 271 /** 272 * Sets the item damage of the ItemStack. 273 */ 274 public void setItemDamage(int par1) 275 { 276 this.itemDamage = par1; 277 278 if (this.itemDamage < 0) 279 { 280 this.itemDamage = 0; 281 } 282 } 283 284 /** 285 * Returns the max damage an item in the stack can take. 286 */ 287 public int getMaxDamage() 288 { 289 return Item.itemsList[this.itemID].getMaxDamage(); 290 } 291 292 public boolean func_96631_a(int par1, Random par2Random) 293 { 294 if (!this.isItemStackDamageable()) 295 { 296 return false; 297 } 298 else 299 { 300 if (par1 > 0) 301 { 302 int j = EnchantmentHelper.getEnchantmentLevel(Enchantment.unbreaking.effectId, this); 303 int k = 0; 304 305 for (int l = 0; j > 0 && l < par1; ++l) 306 { 307 if (EnchantmentDurability.func_92097_a(this, j, par2Random)) 308 { 309 ++k; 310 } 311 } 312 313 par1 -= k; 314 315 if (par1 <= 0) 316 { 317 return false; 318 } 319 } 320 321 this.itemDamage += par1; 322 return this.itemDamage > this.getMaxDamage(); 323 } 324 } 325 326 /** 327 * Damages the item in the ItemStack 328 */ 329 public void damageItem(int par1, EntityLiving par2EntityLiving) 330 { 331 if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode) 332 { 333 if (this.isItemStackDamageable()) 334 { 335 if (this.func_96631_a(par1, par2EntityLiving.getRNG())) 336 { 337 par2EntityLiving.renderBrokenItemStack(this); 338 339 if (par2EntityLiving instanceof EntityPlayer) 340 { 341 ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1); 342 } 343 344 --this.stackSize; 345 346 if (this.stackSize < 0) 347 { 348 this.stackSize = 0; 349 } 350 351 this.itemDamage = 0; 352 } 353 } 354 } 355 } 356 357 /** 358 * Calls the corresponding fct in di 359 */ 360 public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer) 361 { 362 boolean flag = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer); 363 364 if (flag) 365 { 366 par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 367 } 368 } 369 370 public void onBlockDestroyed(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 371 { 372 boolean flag = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer); 373 374 if (flag) 375 { 376 par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 377 } 378 } 379 380 /** 381 * Returns the damage against a given entity. 382 */ 383 public int getDamageVsEntity(Entity par1Entity) 384 { 385 return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity, this); 386 } 387 388 /** 389 * Checks if the itemStack object can harvest a specified block 390 */ 391 public boolean canHarvestBlock(Block par1Block) 392 { 393 return Item.itemsList[this.itemID].canHarvestBlock(par1Block); 394 } 395 396 public boolean interactWith(EntityLiving par1EntityLiving) 397 { 398 return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving); 399 } 400 401 /** 402 * Returns a new stack with the same properties. 403 */ 404 public ItemStack copy() 405 { 406 ItemStack itemstack = new ItemStack(this.itemID, this.stackSize, this.itemDamage); 407 408 if (this.stackTagCompound != null) 409 { 410 itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy(); 411 } 412 413 return itemstack; 414 } 415 416 public static boolean areItemStackTagsEqual(ItemStack par0ItemStack, ItemStack par1ItemStack) 417 { 418 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? (par0ItemStack.stackTagCompound == null && par1ItemStack.stackTagCompound != null ? false : par0ItemStack.stackTagCompound == null || par0ItemStack.stackTagCompound.equals(par1ItemStack.stackTagCompound)) : false); 419 } 420 421 /** 422 * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal 423 */ 424 public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack) 425 { 426 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false); 427 } 428 429 /** 430 * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal 431 */ 432 private boolean isItemStackEqual(ItemStack par1ItemStack) 433 { 434 return this.stackSize != par1ItemStack.stackSize ? false : (this.itemID != par1ItemStack.itemID ? false : (this.itemDamage != par1ItemStack.itemDamage ? false : (this.stackTagCompound == null && par1ItemStack.stackTagCompound != null ? false : this.stackTagCompound == null || this.stackTagCompound.equals(par1ItemStack.stackTagCompound)))); 435 } 436 437 /** 438 * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are 439 * equal 440 */ 441 public boolean isItemEqual(ItemStack par1ItemStack) 442 { 443 return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage; 444 } 445 446 public String getItemName() 447 { 448 return Item.itemsList[this.itemID].getUnlocalizedName(this); 449 } 450 451 /** 452 * Creates a copy of a ItemStack, a null parameters will return a null. 453 */ 454 public static ItemStack copyItemStack(ItemStack par0ItemStack) 455 { 456 return par0ItemStack == null ? null : par0ItemStack.copy(); 457 } 458 459 public String toString() 460 { 461 return this.stackSize + "x" + Item.itemsList[this.itemID].getUnlocalizedName() + "@" + this.itemDamage; 462 } 463 464 /** 465 * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update 466 * maps. 467 */ 468 public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4) 469 { 470 if (this.animationsToGo > 0) 471 { 472 --this.animationsToGo; 473 } 474 475 Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4); 476 } 477 478 public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3) 479 { 480 par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3); 481 Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer); 482 } 483 484 public int getMaxItemUseDuration() 485 { 486 return this.getItem().getMaxItemUseDuration(this); 487 } 488 489 public EnumAction getItemUseAction() 490 { 491 return this.getItem().getItemUseAction(this); 492 } 493 494 /** 495 * Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount 496 */ 497 public void onPlayerStoppedUsing(World par1World, EntityPlayer par2EntityPlayer, int par3) 498 { 499 this.getItem().onPlayerStoppedUsing(this, par1World, par2EntityPlayer, par3); 500 } 501 502 /** 503 * Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments. 504 */ 505 public boolean hasTagCompound() 506 { 507 return this.stackTagCompound != null; 508 } 509 510 /** 511 * Returns the NBTTagCompound of the ItemStack. 512 */ 513 public NBTTagCompound getTagCompound() 514 { 515 return this.stackTagCompound; 516 } 517 518 public NBTTagList getEnchantmentTagList() 519 { 520 return this.stackTagCompound == null ? null : (NBTTagList)this.stackTagCompound.getTag("ench"); 521 } 522 523 /** 524 * Assigns a NBTTagCompound to the ItemStack, minecraft validates that only non-stackable items can have it. 525 */ 526 public void setTagCompound(NBTTagCompound par1NBTTagCompound) 527 { 528 this.stackTagCompound = par1NBTTagCompound; 529 } 530 531 /** 532 * returns the display name of the itemstack 533 */ 534 public String getDisplayName() 535 { 536 String s = this.getItem().getItemDisplayName(this); 537 538 if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display")) 539 { 540 NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display"); 541 542 if (nbttagcompound.hasKey("Name")) 543 { 544 s = nbttagcompound.getString("Name"); 545 } 546 } 547 548 return s; 549 } 550 551 /** 552 * Sets the item's name (used by anvil to rename the items). 553 */ 554 public void setItemName(String par1Str) 555 { 556 if (this.stackTagCompound == null) 557 { 558 this.stackTagCompound = new NBTTagCompound("tag"); 559 } 560 561 if (!this.stackTagCompound.hasKey("display")) 562 { 563 this.stackTagCompound.setCompoundTag("display", new NBTTagCompound()); 564 } 565 566 this.stackTagCompound.getCompoundTag("display").setString("Name", par1Str); 567 } 568 569 /** 570 * Returns true if the itemstack has a display name 571 */ 572 public boolean hasDisplayName() 573 { 574 return this.stackTagCompound == null ? false : (!this.stackTagCompound.hasKey("display") ? false : this.stackTagCompound.getCompoundTag("display").hasKey("Name")); 575 } 576 577 @SideOnly(Side.CLIENT) 578 579 /** 580 * Return a list of strings containing information about the item 581 */ 582 public List getTooltip(EntityPlayer par1EntityPlayer, boolean par2) 583 { 584 ArrayList arraylist = new ArrayList(); 585 Item item = Item.itemsList[this.itemID]; 586 String s = this.getDisplayName(); 587 588 if (this.hasDisplayName()) 589 { 590 s = EnumChatFormatting.ITALIC + s + EnumChatFormatting.RESET; 591 } 592 593 if (par2) 594 { 595 String s1 = ""; 596 597 if (s.length() > 0) 598 { 599 s = s + " ("; 600 s1 = ")"; 601 } 602 603 if (this.getHasSubtypes()) 604 { 605 s = s + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), s1}); 606 } 607 else 608 { 609 s = s + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), s1}); 610 } 611 } 612 else if (!this.hasDisplayName() && this.itemID == Item.map.itemID) 613 { 614 s = s + " #" + this.itemDamage; 615 } 616 617 arraylist.add(s); 618 item.addInformation(this, par1EntityPlayer, arraylist, par2); 619 620 if (this.hasTagCompound()) 621 { 622 NBTTagList nbttaglist = this.getEnchantmentTagList(); 623 624 if (nbttaglist != null) 625 { 626 for (int i = 0; i < nbttaglist.tagCount(); ++i) 627 { 628 short short1 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("id"); 629 short short2 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("lvl"); 630 631 if (Enchantment.enchantmentsList[short1] != null) 632 { 633 arraylist.add(Enchantment.enchantmentsList[short1].getTranslatedName(short2)); 634 } 635 } 636 } 637 638 if (this.stackTagCompound.hasKey("display")) 639 { 640 NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display"); 641 642 if (nbttagcompound.hasKey("color")) 643 { 644 if (par2) 645 { 646 arraylist.add("Color: #" + Integer.toHexString(nbttagcompound.getInteger("color")).toUpperCase()); 647 } 648 else 649 { 650 arraylist.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("item.dyed")); 651 } 652 } 653 654 if (nbttagcompound.hasKey("Lore")) 655 { 656 NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore"); 657 658 if (nbttaglist1.tagCount() > 0) 659 { 660 for (int j = 0; j < nbttaglist1.tagCount(); ++j) 661 { 662 arraylist.add(EnumChatFormatting.DARK_PURPLE + "" + EnumChatFormatting.ITALIC + ((NBTTagString)nbttaglist1.tagAt(j)).data); 663 } 664 } 665 } 666 } 667 } 668 669 if (par2 && this.isItemDamaged()) 670 { 671 arraylist.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage()); 672 } 673 674 return arraylist; 675 } 676 677 @SideOnly(Side.CLIENT) 678 public boolean hasEffect() 679 { 680 return this.getItem().hasEffect(this); 681 } 682 683 @SideOnly(Side.CLIENT) 684 public EnumRarity getRarity() 685 { 686 return this.getItem().getRarity(this); 687 } 688 689 /** 690 * True if it is a tool and has no enchantments to begin with 691 */ 692 public boolean isItemEnchantable() 693 { 694 return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted(); 695 } 696 697 /** 698 * Adds an enchantment with a desired level on the ItemStack. 699 */ 700 public void addEnchantment(Enchantment par1Enchantment, int par2) 701 { 702 if (this.stackTagCompound == null) 703 { 704 this.setTagCompound(new NBTTagCompound()); 705 } 706 707 if (!this.stackTagCompound.hasKey("ench")) 708 { 709 this.stackTagCompound.setTag("ench", new NBTTagList("ench")); 710 } 711 712 NBTTagList nbttaglist = (NBTTagList)this.stackTagCompound.getTag("ench"); 713 NBTTagCompound nbttagcompound = new NBTTagCompound(); 714 nbttagcompound.setShort("id", (short)par1Enchantment.effectId); 715 nbttagcompound.setShort("lvl", (short)((byte)par2)); 716 nbttaglist.appendTag(nbttagcompound); 717 } 718 719 /** 720 * True if the item has enchantment data 721 */ 722 public boolean isItemEnchanted() 723 { 724 return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench"); 725 } 726 727 public void setTagInfo(String par1Str, NBTBase par2NBTBase) 728 { 729 if (this.stackTagCompound == null) 730 { 731 this.setTagCompound(new NBTTagCompound()); 732 } 733 734 this.stackTagCompound.setTag(par1Str, par2NBTBase); 735 } 736 737 public boolean func_82835_x() 738 { 739 return this.getItem().func_82788_x(); 740 } 741 742 /** 743 * Return whether this stack is on an item frame. 744 */ 745 public boolean isOnItemFrame() 746 { 747 return this.itemFrame != null; 748 } 749 750 /** 751 * Set the item frame this stack is on. 752 */ 753 public void setItemFrame(EntityItemFrame par1EntityItemFrame) 754 { 755 this.itemFrame = par1EntityItemFrame; 756 } 757 758 /** 759 * Return the item frame this stack is on. Returns null if not on an item frame. 760 */ 761 public EntityItemFrame getItemFrame() 762 { 763 return this.itemFrame; 764 } 765 766 /** 767 * Get this stack's repair cost, or 0 if no repair cost is defined. 768 */ 769 public int getRepairCost() 770 { 771 return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0; 772 } 773 774 /** 775 * Set this stack's repair cost. 776 */ 777 public void setRepairCost(int par1) 778 { 779 if (!this.hasTagCompound()) 780 { 781 this.stackTagCompound = new NBTTagCompound("tag"); 782 } 783 784 this.stackTagCompound.setInteger("RepairCost", par1); 785 } 786}