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