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 }