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    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.getItem().isItemStackDamaged(this);
253    }
254
255    /**
256     * gets the damage of an itemstack, for displaying purposes
257     */
258    public int getItemDamageForDisplay()
259    {
260        return this.getItem().getItemDamageFromStackForDisplay(this);
261    }
262
263    /**
264     * gets the damage of an itemstack
265     */
266    public int getItemDamage()
267    {
268        return this.getItem().getItemDamageFromStack(this);
269    }
270
271    /**
272     * Sets the item damage of the ItemStack.
273     */
274    public void setItemDamage(int par1)
275    {
276        this.getItem().setItemDamageForStack(this, par1);
277    }
278
279    /**
280     * Returns the max damage an item in the stack can take.
281     */
282    public int getMaxDamage()
283    {
284        return Item.itemsList[this.itemID].getMaxDamage();
285    }
286
287    public boolean func_96631_a(int par1, Random par2Random)
288    {
289        if (!this.isItemStackDamageable())
290        {
291            return false;
292        }
293        else
294        {
295            if (par1 > 0)
296            {
297                int j = EnchantmentHelper.getEnchantmentLevel(Enchantment.unbreaking.effectId, this);
298                int k = 0;
299
300                for (int l = 0; j > 0 && l < par1; ++l)
301                {
302                    if (EnchantmentDurability.func_92097_a(this, j, par2Random))
303                    {
304                        ++k;
305                    }
306                }
307
308                par1 -= k;
309
310                if (par1 <= 0)
311                {
312                    return false;
313                }
314            }
315
316            this.itemDamage += par1;
317            return this.itemDamage > this.getMaxDamage();
318        }
319    }
320
321    /**
322     * Damages the item in the ItemStack
323     */
324    public void damageItem(int par1, EntityLiving par2EntityLiving)
325    {
326        if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode)
327        {
328            if (this.isItemStackDamageable())
329            {
330                if (this.func_96631_a(par1, par2EntityLiving.getRNG()))
331                {
332                    par2EntityLiving.renderBrokenItemStack(this);
333
334                    if (par2EntityLiving instanceof EntityPlayer)
335                    {
336                        ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1);
337                    }
338
339                    --this.stackSize;
340
341                    if (this.stackSize < 0)
342                    {
343                        this.stackSize = 0;
344                    }
345
346                    this.itemDamage = 0;
347                }
348            }
349        }
350    }
351
352    /**
353     * Calls the corresponding fct in di
354     */
355    public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer)
356    {
357        boolean flag = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer);
358
359        if (flag)
360        {
361            par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
362        }
363    }
364
365    public void onBlockDestroyed(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
366    {
367        boolean flag = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer);
368
369        if (flag)
370        {
371            par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
372        }
373    }
374
375    /**
376     * Returns the damage against a given entity.
377     */
378    public int getDamageVsEntity(Entity par1Entity)
379    {
380        return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity, this);
381    }
382
383    /**
384     * Checks if the itemStack object can harvest a specified block
385     */
386    public boolean canHarvestBlock(Block par1Block)
387    {
388        return Item.itemsList[this.itemID].canHarvestBlock(par1Block);
389    }
390
391    public boolean interactWith(EntityLiving par1EntityLiving)
392    {
393        return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving);
394    }
395
396    /**
397     * Returns a new stack with the same properties.
398     */
399    public ItemStack copy()
400    {
401        ItemStack itemstack = new ItemStack(this.itemID, this.stackSize, this.itemDamage);
402
403        if (this.stackTagCompound != null)
404        {
405            itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
406        }
407
408        return itemstack;
409    }
410
411    public static boolean areItemStackTagsEqual(ItemStack par0ItemStack, ItemStack par1ItemStack)
412    {
413        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);
414    }
415
416    /**
417     * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal
418     */
419    public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack)
420    {
421        return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false);
422    }
423
424    /**
425     * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal
426     */
427    private boolean isItemStackEqual(ItemStack par1ItemStack)
428    {
429        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))));
430    }
431
432    /**
433     * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are
434     * equal
435     */
436    public boolean isItemEqual(ItemStack par1ItemStack)
437    {
438        return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage;
439    }
440
441    public String getItemName()
442    {
443        return Item.itemsList[this.itemID].getUnlocalizedName(this);
444    }
445
446    /**
447     * Creates a copy of a ItemStack, a null parameters will return a null.
448     */
449    public static ItemStack copyItemStack(ItemStack par0ItemStack)
450    {
451        return par0ItemStack == null ? null : par0ItemStack.copy();
452    }
453
454    public String toString()
455    {
456        return this.stackSize + "x" + Item.itemsList[this.itemID].getUnlocalizedName() + "@" + this.itemDamage;
457    }
458
459    /**
460     * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update
461     * maps.
462     */
463    public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4)
464    {
465        if (this.animationsToGo > 0)
466        {
467            --this.animationsToGo;
468        }
469
470        Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4);
471    }
472
473    public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3)
474    {
475        par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3);
476        Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer);
477    }
478
479    public int getMaxItemUseDuration()
480    {
481        return this.getItem().getMaxItemUseDuration(this);
482    }
483
484    public EnumAction getItemUseAction()
485    {
486        return this.getItem().getItemUseAction(this);
487    }
488
489    /**
490     * Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount
491     */
492    public void onPlayerStoppedUsing(World par1World, EntityPlayer par2EntityPlayer, int par3)
493    {
494        this.getItem().onPlayerStoppedUsing(this, par1World, par2EntityPlayer, par3);
495    }
496
497    /**
498     * Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments.
499     */
500    public boolean hasTagCompound()
501    {
502        return this.stackTagCompound != null;
503    }
504
505    /**
506     * Returns the NBTTagCompound of the ItemStack.
507     */
508    public NBTTagCompound getTagCompound()
509    {
510        return this.stackTagCompound;
511    }
512
513    public NBTTagList getEnchantmentTagList()
514    {
515        return this.stackTagCompound == null ? null : (NBTTagList)this.stackTagCompound.getTag("ench");
516    }
517
518    /**
519     * Assigns a NBTTagCompound to the ItemStack, minecraft validates that only non-stackable items can have it.
520     */
521    public void setTagCompound(NBTTagCompound par1NBTTagCompound)
522    {
523        this.stackTagCompound = par1NBTTagCompound;
524    }
525
526    /**
527     * returns the display name of the itemstack
528     */
529    public String getDisplayName()
530    {
531        String s = this.getItem().getItemDisplayName(this);
532
533        if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display"))
534        {
535            NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
536
537            if (nbttagcompound.hasKey("Name"))
538            {
539                s = nbttagcompound.getString("Name");
540            }
541        }
542
543        return s;
544    }
545
546    /**
547     * Sets the item's name (used by anvil to rename the items).
548     */
549    public void setItemName(String par1Str)
550    {
551        if (this.stackTagCompound == null)
552        {
553            this.stackTagCompound = new NBTTagCompound("tag");
554        }
555
556        if (!this.stackTagCompound.hasKey("display"))
557        {
558            this.stackTagCompound.setCompoundTag("display", new NBTTagCompound());
559        }
560
561        this.stackTagCompound.getCompoundTag("display").setString("Name", par1Str);
562    }
563
564    /**
565     * Returns true if the itemstack has a display name
566     */
567    public boolean hasDisplayName()
568    {
569        return this.stackTagCompound == null ? false : (!this.stackTagCompound.hasKey("display") ? false : this.stackTagCompound.getCompoundTag("display").hasKey("Name"));
570    }
571
572    @SideOnly(Side.CLIENT)
573
574    /**
575     * Return a list of strings containing information about the item
576     */
577    public List getTooltip(EntityPlayer par1EntityPlayer, boolean par2)
578    {
579        ArrayList arraylist = new ArrayList();
580        Item item = Item.itemsList[this.itemID];
581        String s = this.getDisplayName();
582
583        if (this.hasDisplayName())
584        {
585            s = EnumChatFormatting.ITALIC + s + EnumChatFormatting.RESET;
586        }
587
588        if (par2)
589        {
590            String s1 = "";
591
592            if (s.length() > 0)
593            {
594                s = s + " (";
595                s1 = ")";
596            }
597
598            if (this.getHasSubtypes())
599            {
600                s = s + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), s1});
601            }
602            else
603            {
604                s = s + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), s1});
605            }
606        }
607        else if (!this.hasDisplayName() && this.itemID == Item.map.itemID)
608        {
609            s = s + " #" + this.itemDamage;
610        }
611
612        arraylist.add(s);
613        item.addInformation(this, par1EntityPlayer, arraylist, par2);
614
615        if (this.hasTagCompound())
616        {
617            NBTTagList nbttaglist = this.getEnchantmentTagList();
618
619            if (nbttaglist != null)
620            {
621                for (int i = 0; i < nbttaglist.tagCount(); ++i)
622                {
623                    short short1 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("id");
624                    short short2 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("lvl");
625
626                    if (Enchantment.enchantmentsList[short1] != null)
627                    {
628                        arraylist.add(Enchantment.enchantmentsList[short1].getTranslatedName(short2));
629                    }
630                }
631            }
632
633            if (this.stackTagCompound.hasKey("display"))
634            {
635                NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
636
637                if (nbttagcompound.hasKey("color"))
638                {
639                    if (par2)
640                    {
641                        arraylist.add("Color: #" + Integer.toHexString(nbttagcompound.getInteger("color")).toUpperCase());
642                    }
643                    else
644                    {
645                        arraylist.add(EnumChatFormatting.ITALIC + StatCollector.translateToLocal("item.dyed"));
646                    }
647                }
648
649                if (nbttagcompound.hasKey("Lore"))
650                {
651                    NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore");
652
653                    if (nbttaglist1.tagCount() > 0)
654                    {
655                        for (int j = 0; j < nbttaglist1.tagCount(); ++j)
656                        {
657                            arraylist.add(EnumChatFormatting.DARK_PURPLE + "" + EnumChatFormatting.ITALIC + ((NBTTagString)nbttaglist1.tagAt(j)).data);
658                        }
659                    }
660                }
661            }
662        }
663
664        if (par2 && this.isItemDamaged())
665        {
666            arraylist.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage());
667        }
668
669        return arraylist;
670    }
671
672    @SideOnly(Side.CLIENT)
673    public boolean hasEffect()
674    {
675        return this.getItem().hasEffect(this);
676    }
677
678    @SideOnly(Side.CLIENT)
679    public EnumRarity getRarity()
680    {
681        return this.getItem().getRarity(this);
682    }
683
684    /**
685     * True if it is a tool and has no enchantments to begin with
686     */
687    public boolean isItemEnchantable()
688    {
689        return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
690    }
691
692    /**
693     * Adds an enchantment with a desired level on the ItemStack.
694     */
695    public void addEnchantment(Enchantment par1Enchantment, int par2)
696    {
697        if (this.stackTagCompound == null)
698        {
699            this.setTagCompound(new NBTTagCompound());
700        }
701
702        if (!this.stackTagCompound.hasKey("ench"))
703        {
704            this.stackTagCompound.setTag("ench", new NBTTagList("ench"));
705        }
706
707        NBTTagList nbttaglist = (NBTTagList)this.stackTagCompound.getTag("ench");
708        NBTTagCompound nbttagcompound = new NBTTagCompound();
709        nbttagcompound.setShort("id", (short)par1Enchantment.effectId);
710        nbttagcompound.setShort("lvl", (short)((byte)par2));
711        nbttaglist.appendTag(nbttagcompound);
712    }
713
714    /**
715     * True if the item has enchantment data
716     */
717    public boolean isItemEnchanted()
718    {
719        return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench");
720    }
721
722    public void setTagInfo(String par1Str, NBTBase par2NBTBase)
723    {
724        if (this.stackTagCompound == null)
725        {
726            this.setTagCompound(new NBTTagCompound());
727        }
728
729        this.stackTagCompound.setTag(par1Str, par2NBTBase);
730    }
731
732    public boolean func_82835_x()
733    {
734        return this.getItem().func_82788_x();
735    }
736
737    /**
738     * Return whether this stack is on an item frame.
739     */
740    public boolean isOnItemFrame()
741    {
742        return this.itemFrame != null;
743    }
744
745    /**
746     * Set the item frame this stack is on.
747     */
748    public void setItemFrame(EntityItemFrame par1EntityItemFrame)
749    {
750        this.itemFrame = par1EntityItemFrame;
751    }
752
753    /**
754     * Return the item frame this stack is on. Returns null if not on an item frame.
755     */
756    public EntityItemFrame getItemFrame()
757    {
758        return this.itemFrame;
759    }
760
761    /**
762     * Get this stack's repair cost, or 0 if no repair cost is defined.
763     */
764    public int getRepairCost()
765    {
766        return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0;
767    }
768
769    /**
770     * Set this stack's repair cost.
771     */
772    public void setRepairCost(int par1)
773    {
774        if (!this.hasTagCompound())
775        {
776            this.stackTagCompound = new NBTTagCompound("tag");
777        }
778
779        this.stackTagCompound.setInteger("RepairCost", par1);
780    }
781}