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