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 (this.hasDisplayName()) 528 { 529 var5 = "\u00a7o" + var5 + "\u00a7r"; 530 } 531 532 if (par2) 533 { 534 String var6 = ""; 535 536 if (var5.length() > 0) 537 { 538 var5 = var5 + " ("; 539 var6 = ")"; 540 } 541 542 if (this.getHasSubtypes()) 543 { 544 var5 = var5 + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), var6}); 545 } 546 else 547 { 548 var5 = var5 + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), var6}); 549 } 550 } 551 else if (!this.hasDisplayName() && this.itemID == Item.map.shiftedIndex) 552 { 553 var5 = var5 + " #" + this.itemDamage; 554 } 555 556 var3.add(var5); 557 var4.addInformation(this, par1EntityPlayer, var3, par2); 558 559 if (this.hasTagCompound()) 560 { 561 NBTTagList var10 = this.getEnchantmentTagList(); 562 563 if (var10 != null) 564 { 565 for (int var7 = 0; var7 < var10.tagCount(); ++var7) 566 { 567 short var8 = ((NBTTagCompound)var10.tagAt(var7)).getShort("id"); 568 short var9 = ((NBTTagCompound)var10.tagAt(var7)).getShort("lvl"); 569 570 if (Enchantment.enchantmentsList[var8] != null) 571 { 572 var3.add(Enchantment.enchantmentsList[var8].getTranslatedName(var9)); 573 } 574 } 575 } 576 577 if (this.stackTagCompound.hasKey("display")) 578 { 579 NBTTagCompound var11 = this.stackTagCompound.getCompoundTag("display"); 580 581 if (var11.hasKey("color")) 582 { 583 if (par2) 584 { 585 var3.add("Color: #" + Integer.toHexString(var11.getInteger("color")).toUpperCase()); 586 } 587 else 588 { 589 var3.add("\u00a7o" + StatCollector.translateToLocal("item.dyed")); 590 } 591 } 592 593 if (var11.hasKey("Lore")) 594 { 595 NBTTagList var12 = var11.getTagList("Lore"); 596 597 if (var12.tagCount() > 0) 598 { 599 for (int var13 = 0; var13 < var12.tagCount(); ++var13) 600 { 601 var3.add("\u00a75\u00a7o" + ((NBTTagString)var12.tagAt(var13)).data); 602 } 603 } 604 } 605 } 606 } 607 608 if (par2 && this.isItemDamaged()) 609 { 610 var3.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage()); 611 } 612 613 return var3; 614 } 615 616 @SideOnly(Side.CLIENT) 617 public boolean hasEffect() 618 { 619 return this.getItem().hasEffect(this); 620 } 621 622 @SideOnly(Side.CLIENT) 623 public EnumRarity getRarity() 624 { 625 return this.getItem().getRarity(this); 626 } 627 628 /** 629 * True if it is a tool and has no enchantments to begin with 630 */ 631 public boolean isItemEnchantable() 632 { 633 return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted(); 634 } 635 636 /** 637 * Adds an enchantment with a desired level on the ItemStack. 638 */ 639 public void addEnchantment(Enchantment par1Enchantment, int par2) 640 { 641 if (this.stackTagCompound == null) 642 { 643 this.setTagCompound(new NBTTagCompound()); 644 } 645 646 if (!this.stackTagCompound.hasKey("ench")) 647 { 648 this.stackTagCompound.setTag("ench", new NBTTagList("ench")); 649 } 650 651 NBTTagList var3 = (NBTTagList)this.stackTagCompound.getTag("ench"); 652 NBTTagCompound var4 = new NBTTagCompound(); 653 var4.setShort("id", (short)par1Enchantment.effectId); 654 var4.setShort("lvl", (short)((byte)par2)); 655 var3.appendTag(var4); 656 } 657 658 /** 659 * True if the item has enchantment data 660 */ 661 public boolean isItemEnchanted() 662 { 663 return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench"); 664 } 665 666 public void setTagInfo(String par1Str, NBTBase par2NBTBase) 667 { 668 if (this.stackTagCompound == null) 669 { 670 this.setTagCompound(new NBTTagCompound()); 671 } 672 673 this.stackTagCompound.setTag(par1Str, par2NBTBase); 674 } 675 676 public boolean func_82835_x() 677 { 678 return this.getItem().func_82788_x(); 679 } 680 681 /** 682 * Return whether this stack is on an item frame. 683 */ 684 public boolean isOnItemFrame() 685 { 686 return this.itemFrame != null; 687 } 688 689 /** 690 * Set the item frame this stack is on. 691 */ 692 public void setItemFrame(EntityItemFrame par1EntityItemFrame) 693 { 694 this.itemFrame = par1EntityItemFrame; 695 } 696 697 /** 698 * Return the item frame this stack is on. Returns null if not on an item frame. 699 */ 700 public EntityItemFrame getItemFrame() 701 { 702 return this.itemFrame; 703 } 704 705 /** 706 * Get this stack's repair cost, or 0 if no repair cost is defined. 707 */ 708 public int getRepairCost() 709 { 710 return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0; 711 } 712 713 /** 714 * Set this stack's repair cost. 715 */ 716 public void setRepairCost(int par1) 717 { 718 if (!this.hasTagCompound()) 719 { 720 this.stackTagCompound = new NBTTagCompound(); 721 } 722 723 this.stackTagCompound.setInteger("RepairCost", par1); 724 } 725 }