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