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