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 public ItemStack(Block par1Block) 030 { 031 this(par1Block, 1); 032 } 033 034 public ItemStack(Block par1Block, int par2) 035 { 036 this(par1Block.blockID, par2, 0); 037 } 038 039 public ItemStack(Block par1Block, int par2, int par3) 040 { 041 this(par1Block.blockID, par2, par3); 042 } 043 044 public ItemStack(Item par1Item) 045 { 046 this(par1Item.shiftedIndex, 1, 0); 047 } 048 049 public ItemStack(Item par1Item, int par2) 050 { 051 this(par1Item.shiftedIndex, par2, 0); 052 } 053 054 public ItemStack(Item par1Item, int par2, int par3) 055 { 056 this(par1Item.shiftedIndex, par2, par3); 057 } 058 059 public ItemStack(int par1, int par2, int par3) 060 { 061 this.stackSize = 0; 062 this.itemID = par1; 063 this.stackSize = par2; 064 this.itemDamage = par3; 065 } 066 067 public static ItemStack loadItemStackFromNBT(NBTTagCompound par0NBTTagCompound) 068 { 069 ItemStack var1 = new ItemStack(); 070 var1.readFromNBT(par0NBTTagCompound); 071 return var1.getItem() != null ? var1 : null; 072 } 073 074 private ItemStack() 075 { 076 this.stackSize = 0; 077 } 078 079 /** 080 * Remove the argument from the stack size. Return a new stack object with argument size. 081 */ 082 public ItemStack splitStack(int par1) 083 { 084 ItemStack var2 = new ItemStack(this.itemID, par1, this.itemDamage); 085 086 if (this.stackTagCompound != null) 087 { 088 var2.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy(); 089 } 090 091 this.stackSize -= par1; 092 return var2; 093 } 094 095 /** 096 * Returns the object corresponding to the stack. 097 */ 098 public Item getItem() 099 { 100 return Item.itemsList[this.itemID]; 101 } 102 103 @SideOnly(Side.CLIENT) 104 105 /** 106 * Returns the icon index of the current stack. 107 */ 108 public int getIconIndex() 109 { 110 return this.getItem().getIconIndex(this); 111 } 112 113 public boolean tryPlaceItemIntoWorld(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5, int par6, float par7, float par8, float par9) 114 { 115 boolean var10 = this.getItem().onItemUse(this, par1EntityPlayer, par2World, par3, par4, par5, par6, par7, par8, par9); 116 117 if (var10) 118 { 119 par1EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 120 } 121 122 return var10; 123 } 124 125 /** 126 * Returns the strength of the stack against a given block. 127 */ 128 public float getStrVsBlock(Block par1Block) 129 { 130 return this.getItem().getStrVsBlock(this, par1Block); 131 } 132 133 /** 134 * Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position 135 * where this item is. Args: world, player 136 */ 137 public ItemStack useItemRightClick(World par1World, EntityPlayer par2EntityPlayer) 138 { 139 return this.getItem().onItemRightClick(this, par1World, par2EntityPlayer); 140 } 141 142 public ItemStack onFoodEaten(World par1World, EntityPlayer par2EntityPlayer) 143 { 144 return this.getItem().onFoodEaten(this, par1World, par2EntityPlayer); 145 } 146 147 /** 148 * Write the stack fields to a NBT object. Return the new NBT object. 149 */ 150 public NBTTagCompound writeToNBT(NBTTagCompound par1NBTTagCompound) 151 { 152 par1NBTTagCompound.setShort("id", (short)this.itemID); 153 par1NBTTagCompound.setByte("Count", (byte)this.stackSize); 154 par1NBTTagCompound.setShort("Damage", (short)this.itemDamage); 155 156 if (this.stackTagCompound != null) 157 { 158 par1NBTTagCompound.setTag("tag", this.stackTagCompound); 159 } 160 161 return par1NBTTagCompound; 162 } 163 164 /** 165 * Read the stack fields from a NBT object. 166 */ 167 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 168 { 169 this.itemID = par1NBTTagCompound.getShort("id"); 170 this.stackSize = par1NBTTagCompound.getByte("Count"); 171 this.itemDamage = par1NBTTagCompound.getShort("Damage"); 172 173 if (par1NBTTagCompound.hasKey("tag")) 174 { 175 this.stackTagCompound = par1NBTTagCompound.getCompoundTag("tag"); 176 } 177 } 178 179 /** 180 * Returns maximum size of the stack. 181 */ 182 public int getMaxStackSize() 183 { 184 return this.getItem().getItemStackLimit(); 185 } 186 187 /** 188 * Returns true if the ItemStack can hold 2 or more units of the item. 189 */ 190 public boolean isStackable() 191 { 192 return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged()); 193 } 194 195 /** 196 * true if this itemStack is damageable 197 */ 198 public boolean isItemStackDamageable() 199 { 200 return Item.itemsList[this.itemID].getMaxDamage() > 0; 201 } 202 203 public boolean getHasSubtypes() 204 { 205 return Item.itemsList[this.itemID].getHasSubtypes(); 206 } 207 208 /** 209 * returns true when a damageable item is damaged 210 */ 211 public boolean isItemDamaged() 212 { 213 return this.isItemStackDamageable() && this.itemDamage > 0; 214 } 215 216 /** 217 * gets the damage of an itemstack, for displaying purposes 218 */ 219 public int getItemDamageForDisplay() 220 { 221 return this.itemDamage; 222 } 223 224 /** 225 * gets the damage of an itemstack 226 */ 227 public int getItemDamage() 228 { 229 return this.itemDamage; 230 } 231 232 /** 233 * Sets the item damage of the ItemStack. 234 */ 235 public void setItemDamage(int par1) 236 { 237 this.itemDamage = par1; 238 } 239 240 /** 241 * Returns the max damage an item in the stack can take. 242 */ 243 public int getMaxDamage() 244 { 245 return Item.itemsList[this.itemID].getMaxDamage(); 246 } 247 248 /** 249 * Damages the item in the ItemStack 250 */ 251 public void damageItem(int par1, EntityLiving par2EntityLiving) 252 { 253 if (this.isItemStackDamageable()) 254 { 255 if (par1 > 0 && par2EntityLiving instanceof EntityPlayer) 256 { 257 int var3 = EnchantmentHelper.getUnbreakingModifier(((EntityPlayer)par2EntityLiving).inventory); 258 259 if (var3 > 0 && par2EntityLiving.worldObj.rand.nextInt(var3 + 1) > 0) 260 { 261 return; 262 } 263 } 264 265 if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode) 266 { 267 this.itemDamage += par1; 268 } 269 270 if (this.itemDamage > this.getMaxDamage()) 271 { 272 par2EntityLiving.renderBrokenItemStack(this); 273 274 if (par2EntityLiving instanceof EntityPlayer) 275 { 276 ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1); 277 } 278 279 --this.stackSize; 280 281 if (this.stackSize < 0) 282 { 283 this.stackSize = 0; 284 } 285 286 this.itemDamage = 0; 287 } 288 } 289 } 290 291 /** 292 * Calls the corresponding fct in di 293 */ 294 public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer) 295 { 296 boolean var3 = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer); 297 298 if (var3) 299 { 300 par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 301 } 302 } 303 304 public void func_77941_a(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) 305 { 306 boolean var7 = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer); 307 308 if (var7) 309 { 310 par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1); 311 } 312 } 313 314 /** 315 * Returns the damage against a given entity. 316 */ 317 public int getDamageVsEntity(Entity par1Entity) 318 { 319 return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity); 320 } 321 322 /** 323 * Checks if the itemStack object can harvest a specified block 324 */ 325 public boolean canHarvestBlock(Block par1Block) 326 { 327 return Item.itemsList[this.itemID].canHarvestBlock(par1Block); 328 } 329 330 public boolean interactWith(EntityLiving par1EntityLiving) 331 { 332 return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving); 333 } 334 335 /** 336 * Returns a new stack with the same properties. 337 */ 338 public ItemStack copy() 339 { 340 ItemStack var1 = new ItemStack(this.itemID, this.stackSize, this.itemDamage); 341 342 if (this.stackTagCompound != null) 343 { 344 var1.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy(); 345 } 346 347 return var1; 348 } 349 350 public static boolean func_77970_a(ItemStack par0ItemStack, ItemStack par1ItemStack) 351 { 352 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); 353 } 354 355 /** 356 * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal 357 */ 358 public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack) 359 { 360 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false); 361 } 362 363 /** 364 * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal 365 */ 366 private boolean isItemStackEqual(ItemStack par1ItemStack) 367 { 368 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)))); 369 } 370 371 /** 372 * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are 373 * equal 374 */ 375 public boolean isItemEqual(ItemStack par1ItemStack) 376 { 377 return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage; 378 } 379 380 public String getItemName() 381 { 382 return Item.itemsList[this.itemID].getItemNameIS(this); 383 } 384 385 /** 386 * Creates a copy of a ItemStack, a null parameters will return a null. 387 */ 388 public static ItemStack copyItemStack(ItemStack par0ItemStack) 389 { 390 return par0ItemStack == null ? null : par0ItemStack.copy(); 391 } 392 393 public String toString() 394 { 395 return this.stackSize + "x" + Item.itemsList[this.itemID].getItemName() + "@" + this.itemDamage; 396 } 397 398 /** 399 * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update 400 * maps. 401 */ 402 public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4) 403 { 404 if (this.animationsToGo > 0) 405 { 406 --this.animationsToGo; 407 } 408 409 Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4); 410 } 411 412 public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3) 413 { 414 par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3); 415 Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer); 416 } 417 418 public boolean isStackEqual(ItemStack par1ItemStack) 419 { 420 return this.itemID == par1ItemStack.itemID && this.stackSize == par1ItemStack.stackSize && this.itemDamage == par1ItemStack.itemDamage; 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 @SideOnly(Side.CLIENT) 471 472 /** 473 * gets a list of strings representing the item name and successive extra data, eg Enchantments and potion effects 474 */ 475 public List getItemNameandInformation() 476 { 477 ArrayList var1 = new ArrayList(); 478 Item var2 = Item.itemsList[this.itemID]; 479 var1.add(var2.getItemDisplayName(this)); 480 var2.addInformation(this, var1); 481 482 if (this.hasTagCompound()) 483 { 484 NBTTagList var3 = this.getEnchantmentTagList(); 485 486 if (var3 != null) 487 { 488 for (int var4 = 0; var4 < var3.tagCount(); ++var4) 489 { 490 short var5 = ((NBTTagCompound)var3.tagAt(var4)).getShort("id"); 491 short var6 = ((NBTTagCompound)var3.tagAt(var4)).getShort("lvl"); 492 493 if (Enchantment.enchantmentsList[var5] != null) 494 { 495 var1.add(Enchantment.enchantmentsList[var5].getTranslatedName(var6)); 496 } 497 } 498 } 499 } 500 501 return var1; 502 } 503 504 @SideOnly(Side.CLIENT) 505 public boolean hasEffect() 506 { 507 return this.getItem().hasEffect(this); 508 } 509 510 @SideOnly(Side.CLIENT) 511 public EnumRarity getRarity() 512 { 513 return this.getItem().getRarity(this); 514 } 515 516 /** 517 * True if it is a tool and has no enchantments to begin with 518 */ 519 public boolean isItemEnchantable() 520 { 521 return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted(); 522 } 523 524 /** 525 * Adds an enchantment with a desired level on the ItemStack. 526 */ 527 public void addEnchantment(Enchantment par1Enchantment, int par2) 528 { 529 if (this.stackTagCompound == null) 530 { 531 this.setTagCompound(new NBTTagCompound()); 532 } 533 534 if (!this.stackTagCompound.hasKey("ench")) 535 { 536 this.stackTagCompound.setTag("ench", new NBTTagList("ench")); 537 } 538 539 NBTTagList var3 = (NBTTagList)this.stackTagCompound.getTag("ench"); 540 NBTTagCompound var4 = new NBTTagCompound(); 541 var4.setShort("id", (short)par1Enchantment.effectId); 542 var4.setShort("lvl", (short)((byte)par2)); 543 var3.appendTag(var4); 544 } 545 546 /** 547 * True if the item has enchantment data 548 */ 549 public boolean isItemEnchanted() 550 { 551 return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench"); 552 } 553 554 @SideOnly(Side.CLIENT) 555 public void func_77983_a(String par1Str, NBTBase par2NBTBase) 556 { 557 if (this.stackTagCompound == null) 558 { 559 this.setTagCompound(new NBTTagCompound()); 560 } 561 562 this.stackTagCompound.setTag(par1Str, par2NBTBase); 563 } 564 }