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    }