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 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.getItem().isItemStackDamaged(this); 253 } 254 255 /** 256 * gets the damage of an itemstack, for displaying purposes 257 */ 258 public int getItemDamageForDisplay() 259 { 260 return this.getItem().getItemDamageFromStackForDisplay(this); 261 } 262 263 /** 264 * gets the damage of an itemstack 265 */ 266 public int getItemDamage() 267 { 268 return this.getItem().getItemDamageFromStack(this); 269 } 270 271 /** 272 * Sets the item damage of the ItemStack. 273 */ 274 public void setItemDamage(int par1) 275 { 276 this.getItem().setItemDamageForStack(this, par1); 277 } 278 279 /** 280 * Returns the max damage an item in the stack can take. 281 */ 282 public int getMaxDamage() 283 { 284 return Item.itemsList[this.itemID].getMaxDamage(); 285 } 286 287 public boolean func_96631_a(int par1, Random par2Random) 288 { 289 if (!this.isItemStackDamageable()) 290 { 291 return false; 292 } 293 else 294 { 295 if (par1 > 0) 296 { 297 int j = EnchantmentHelper.getEnchantmentLevel(Enchantment.unbreaking.effectId, this); 298 int k = 0; 299 300 for (int l = 0; j > 0 && l < par1; ++l) 301 { 302 if (EnchantmentDurability.func_92097_a(this, j, par2Random)) 303 { 304 ++k; 305 } 306 } 307 308 par1 -= k; 309 310 if (par1 <= 0) 311 { 312 return false; 313 } 314 } 315 316 this.itemDamage += par1; 317 return this.itemDamage > this.getMaxDamage(); 318 } 319 } 320 321 /** 322 * Damages the item in the ItemStack 323 */ 324 public void damageItem(int par1, EntityLiving par2EntityLiving) 325 { 326 if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode) 327 { 328 if (this.isItemStackDamageable()) 329 { 330 if (this.func_96631_a(par1, par2EntityLiving.getRNG())) 331 { 332 par2EntityLiving.renderBrokenItemStack(this); 333 334 if (par2EntityLiving instanceof EntityPlayer) 335 { 336 ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1); 337 } 338 339 --this.stackSize; 340 341 if (this.stackSize < 0) 342 { 343 this.stackSize = 0; 344 } 345 346 this.itemDamage = 0; 347 } 348 } 349 } 350 } 351 352 /** 353 * Calls the corresponding fct in di 354 */ 355 public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer) 356 { 357 boolean flag = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer); 358 359 if (flag) 360 { 361 par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 362 } 363 } 364 365 public void onBlockDestroyed(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 366 { 367 boolean flag = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer); 368 369 if (flag) 370 { 371 par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 372 } 373 } 374 375 /** 376 * Returns the damage against a given entity. 377 */ 378 public int getDamageVsEntity(Entity par1Entity) 379 { 380 return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity, this); 381 } 382 383 /** 384 * Checks if the itemStack object can harvest a specified block 385 */ 386 public boolean canHarvestBlock(Block par1Block) 387 { 388 return Item.itemsList[this.itemID].canHarvestBlock(par1Block); 389 } 390 391 public boolean interactWith(EntityLiving par1EntityLiving) 392 { 393 return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving); 394 } 395 396 /** 397 * Returns a new stack with the same properties. 398 */ 399 public ItemStack copy() 400 { 401 ItemStack itemstack = new ItemStack(this.itemID, this.stackSize, this.itemDamage); 402 403 if (this.stackTagCompound != null) 404 { 405 itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy(); 406 } 407 408 return itemstack; 409 } 410 411 public static boolean areItemStackTagsEqual(ItemStack par0ItemStack, ItemStack par1ItemStack) 412 { 413 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); 414 } 415 416 /** 417 * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal 418 */ 419 public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack) 420 { 421 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false); 422 } 423 424 /** 425 * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal 426 */ 427 private boolean isItemStackEqual(ItemStack par1ItemStack) 428 { 429 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)))); 430 } 431 432 /** 433 * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are 434 * equal 435 */ 436 public boolean isItemEqual(ItemStack par1ItemStack) 437 { 438 return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage; 439 } 440 441 public String getItemName() 442 { 443 return Item.itemsList[this.itemID].getUnlocalizedName(this); 444 } 445 446 /** 447 * Creates a copy of a ItemStack, a null parameters will return a null. 448 */ 449 public static ItemStack copyItemStack(ItemStack par0ItemStack) 450 { 451 return par0ItemStack == null ? null : par0ItemStack.copy(); 452 } 453 454 public String toString() 455 { 456 return this.stackSize + "x" + Item.itemsList[this.itemID].getUnlocalizedName() + "@" + this.itemDamage; 457 } 458 459 /** 460 * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update 461 * maps. 462 */ 463 public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4) 464 { 465 if (this.animationsToGo > 0) 466 { 467 --this.animationsToGo; 468 } 469 470 Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4); 471 } 472 473 public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3) 474 { 475 par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3); 476 Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer); 477 } 478 479 public int getMaxItemUseDuration() 480 { 481 return this.getItem().getMaxItemUseDuration(this); 482 } 483 484 public EnumAction getItemUseAction() 485 { 486 return this.getItem().getItemUseAction(this); 487 } 488 489 /** 490 * Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount 491 */ 492 public void onPlayerStoppedUsing(World par1World, EntityPlayer par2EntityPlayer, int par3) 493 { 494 this.getItem().onPlayerStoppedUsing(this, par1World, par2EntityPlayer, par3); 495 } 496 497 /** 498 * Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments. 499 */ 500 public boolean hasTagCompound() 501 { 502 return this.stackTagCompound != null; 503 } 504 505 /** 506 * Returns the NBTTagCompound of the ItemStack. 507 */ 508 public NBTTagCompound getTagCompound() 509 { 510 return this.stackTagCompound; 511 } 512 513 public NBTTagList getEnchantmentTagList() 514 { 515 return this.stackTagCompound == null ? null : (NBTTagList)this.stackTagCompound.getTag("ench"); 516 } 517 518 /** 519 * Assigns a NBTTagCompound to the ItemStack, minecraft validates that only non-stackable items can have it. 520 */ 521 public void setTagCompound(NBTTagCompound par1NBTTagCompound) 522 { 523 this.stackTagCompound = par1NBTTagCompound; 524 } 525 526 /** 527 * returns the display name of the itemstack 528 */ 529 public String getDisplayName() 530 { 531 String s = this.getItem().getItemDisplayName(this); 532 533 if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display")) 534 { 535 NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display"); 536 537 if (nbttagcompound.hasKey("Name")) 538 { 539 s = nbttagcompound.getString("Name"); 540 } 541 } 542 543 return s; 544 } 545 546 /** 547 * Sets the item's name (used by anvil to rename the items). 548 */ 549 public void setItemName(String par1Str) 550 { 551 if (this.stackTagCompound == null) 552 { 553 this.stackTagCompound = new NBTTagCompound("tag"); 554 } 555 556 if (!this.stackTagCompound.hasKey("display")) 557 { 558 this.stackTagCompound.setCompoundTag("display", new NBTTagCompound()); 559 } 560 561 this.stackTagCompound.getCompoundTag("display").setString("Name", par1Str); 562 } 563 564 /** 565 * Returns true if the itemstack has a display name 566 */ 567 public boolean hasDisplayName() 568 { 569 return this.stackTagCompound == null ? false : (!this.stackTagCompound.hasKey("display") ? false : this.stackTagCompound.getCompoundTag("display").hasKey("Name")); 570 } 571 572 @SideOnly(Side.CLIENT) 573 574 /** 575 * Return a list of strings containing information about the item 576 */ 577 public List getTooltip(EntityPlayer par1EntityPlayer, boolean par2) 578 { 579 ArrayList arraylist = new ArrayList(); 580 Item item = Item.itemsList[this.itemID]; 581 String s = this.getDisplayName(); 582 583 if (this.hasDisplayName()) 584 { 585 s = EnumChatFormatting.ITALIC + s + EnumChatFormatting.RESET; 586 } 587 588 if (par2) 589 { 590 String s1 = ""; 591 592 if (s.length() > 0) 593 { 594 s = s + " ("; 595 s1 = ")"; 596 } 597 598 if (this.getHasSubtypes()) 599 { 600 s = s + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), s1}); 601 } 602 else 603 { 604 s = s + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), s1}); 605 } 606 } 607 else if (!this.hasDisplayName() && this.itemID == Item.map.itemID) 608 { 609 s = s + " #" + this.itemDamage; 610 } 611 612 arraylist.add(s); 613 item.addInformation(this, par1EntityPlayer, arraylist, par2); 614 615 if (this.hasTagCompound()) 616 { 617 NBTTagList nbttaglist = this.getEnchantmentTagList(); 618 619 if (nbttaglist != null) 620 { 621 for (int i = 0; i < nbttaglist.tagCount(); ++i) 622 { 623 short short1 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("id"); 624 short short2 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("lvl"); 625 626 if (Enchantment.enchantmentsList[short1] != null) 627 { 628 arraylist.add(Enchantment.enchantmentsList[short1].getTranslatedName(short2)); 629 } 630 } 631 } 632 633 if (this.stackTagCompound.hasKey("display")) 634 { 635 NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display"); 636 637 if (nbttagcompound.hasKey("color")) 638 { 639 if (par2) 640 { 641 arraylist.add("Color: #" + Integer.toHexString(nbttagcompound.getInteger("color")).toUpperCase()); 642 } 643 else 644 { 645 arraylist.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("item.dyed")); 646 } 647 } 648 649 if (nbttagcompound.hasKey("Lore")) 650 { 651 NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore"); 652 653 if (nbttaglist1.tagCount() > 0) 654 { 655 for (int j = 0; j < nbttaglist1.tagCount(); ++j) 656 { 657 arraylist.add(EnumChatFormatting.DARK_PURPLE + "" + EnumChatFormatting.ITALIC + ((NBTTagString)nbttaglist1.tagAt(j)).data); 658 } 659 } 660 } 661 } 662 } 663 664 if (par2 && this.isItemDamaged()) 665 { 666 arraylist.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage()); 667 } 668 669 return arraylist; 670 } 671 672 @SideOnly(Side.CLIENT) 673 public boolean hasEffect() 674 { 675 return this.getItem().hasEffect(this); 676 } 677 678 @SideOnly(Side.CLIENT) 679 public EnumRarity getRarity() 680 { 681 return this.getItem().getRarity(this); 682 } 683 684 /** 685 * True if it is a tool and has no enchantments to begin with 686 */ 687 public boolean isItemEnchantable() 688 { 689 return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted(); 690 } 691 692 /** 693 * Adds an enchantment with a desired level on the ItemStack. 694 */ 695 public void addEnchantment(Enchantment par1Enchantment, int par2) 696 { 697 if (this.stackTagCompound == null) 698 { 699 this.setTagCompound(new NBTTagCompound()); 700 } 701 702 if (!this.stackTagCompound.hasKey("ench")) 703 { 704 this.stackTagCompound.setTag("ench", new NBTTagList("ench")); 705 } 706 707 NBTTagList nbttaglist = (NBTTagList)this.stackTagCompound.getTag("ench"); 708 NBTTagCompound nbttagcompound = new NBTTagCompound(); 709 nbttagcompound.setShort("id", (short)par1Enchantment.effectId); 710 nbttagcompound.setShort("lvl", (short)((byte)par2)); 711 nbttaglist.appendTag(nbttagcompound); 712 } 713 714 /** 715 * True if the item has enchantment data 716 */ 717 public boolean isItemEnchanted() 718 { 719 return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench"); 720 } 721 722 public void setTagInfo(String par1Str, NBTBase par2NBTBase) 723 { 724 if (this.stackTagCompound == null) 725 { 726 this.setTagCompound(new NBTTagCompound()); 727 } 728 729 this.stackTagCompound.setTag(par1Str, par2NBTBase); 730 } 731 732 public boolean func_82835_x() 733 { 734 return this.getItem().func_82788_x(); 735 } 736 737 /** 738 * Return whether this stack is on an item frame. 739 */ 740 public boolean isOnItemFrame() 741 { 742 return this.itemFrame != null; 743 } 744 745 /** 746 * Set the item frame this stack is on. 747 */ 748 public void setItemFrame(EntityItemFrame par1EntityItemFrame) 749 { 750 this.itemFrame = par1EntityItemFrame; 751 } 752 753 /** 754 * Return the item frame this stack is on. Returns null if not on an item frame. 755 */ 756 public EntityItemFrame getItemFrame() 757 { 758 return this.itemFrame; 759 } 760 761 /** 762 * Get this stack's repair cost, or 0 if no repair cost is defined. 763 */ 764 public int getRepairCost() 765 { 766 return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0; 767 } 768 769 /** 770 * Set this stack's repair cost. 771 */ 772 public void setRepairCost(int par1) 773 { 774 if (!this.hasTagCompound()) 775 { 776 this.stackTagCompound = new NBTTagCompound("tag"); 777 } 778 779 this.stackTagCompound.setInteger("RepairCost", par1); 780 } 781}