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