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