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 (par2)
528            {
529                String var6 = "";
530    
531                if (var5.length() > 0)
532                {
533                    var5 = var5 + " (";
534                    var6 = ")";
535                }
536    
537                if (this.getHasSubtypes())
538                {
539                    var5 = var5 + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), var6});
540                }
541                else
542                {
543                    var5 = var5 + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), var6});
544                }
545            }
546            else if (!this.hasDisplayName())
547            {
548                if (this.itemID == Item.map.shiftedIndex)
549                {
550                    var5 = var5 + " #" + this.itemDamage;
551                }
552            }
553            else
554            {
555                var5 = "\u00a7o" + var5;
556            }
557    
558            var3.add(var5);
559            var4.addInformation(this, par1EntityPlayer, var3, par2);
560    
561            if (this.hasTagCompound())
562            {
563                NBTTagList var10 = this.getEnchantmentTagList();
564    
565                if (var10 != null)
566                {
567                    for (int var7 = 0; var7 < var10.tagCount(); ++var7)
568                    {
569                        short var8 = ((NBTTagCompound)var10.tagAt(var7)).getShort("id");
570                        short var9 = ((NBTTagCompound)var10.tagAt(var7)).getShort("lvl");
571    
572                        if (Enchantment.enchantmentsList[var8] != null)
573                        {
574                            var3.add(Enchantment.enchantmentsList[var8].getTranslatedName(var9));
575                        }
576                    }
577                }
578    
579                if (this.stackTagCompound.hasKey("display"))
580                {
581                    NBTTagCompound var11 = this.stackTagCompound.getCompoundTag("display");
582    
583                    if (var11.hasKey("color"))
584                    {
585                        if (par2)
586                        {
587                            var3.add("Color: #" + Integer.toHexString(var11.getInteger("color")).toUpperCase());
588                        }
589                        else
590                        {
591                            var3.add("\u00a7o" + StatCollector.translateToLocal("item.dyed"));
592                        }
593                    }
594    
595                    if (var11.hasKey("Lore"))
596                    {
597                        NBTTagList var12 = var11.getTagList("Lore");
598    
599                        if (var12.tagCount() > 0)
600                        {
601                            for (int var13 = 0; var13 < var12.tagCount(); ++var13)
602                            {
603                                var3.add("\u00a75\u00a7o" + ((NBTTagString)var12.tagAt(var13)).data);
604                            }
605                        }
606                    }
607                }
608            }
609    
610            if (par2 && this.isItemDamaged())
611            {
612                var3.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage());
613            }
614    
615            return var3;
616        }
617    
618        @SideOnly(Side.CLIENT)
619        public boolean hasEffect()
620        {
621            return this.getItem().hasEffect(this);
622        }
623    
624        @SideOnly(Side.CLIENT)
625        public EnumRarity getRarity()
626        {
627            return this.getItem().getRarity(this);
628        }
629    
630        /**
631         * True if it is a tool and has no enchantments to begin with
632         */
633        public boolean isItemEnchantable()
634        {
635            return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
636        }
637    
638        /**
639         * Adds an enchantment with a desired level on the ItemStack.
640         */
641        public void addEnchantment(Enchantment par1Enchantment, int par2)
642        {
643            if (this.stackTagCompound == null)
644            {
645                this.setTagCompound(new NBTTagCompound());
646            }
647    
648            if (!this.stackTagCompound.hasKey("ench"))
649            {
650                this.stackTagCompound.setTag("ench", new NBTTagList("ench"));
651            }
652    
653            NBTTagList var3 = (NBTTagList)this.stackTagCompound.getTag("ench");
654            NBTTagCompound var4 = new NBTTagCompound();
655            var4.setShort("id", (short)par1Enchantment.effectId);
656            var4.setShort("lvl", (short)((byte)par2));
657            var3.appendTag(var4);
658        }
659    
660        /**
661         * True if the item has enchantment data
662         */
663        public boolean isItemEnchanted()
664        {
665            return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench");
666        }
667    
668        public void func_77983_a(String par1Str, NBTBase par2NBTBase)
669        {
670            if (this.stackTagCompound == null)
671            {
672                this.setTagCompound(new NBTTagCompound());
673            }
674    
675            this.stackTagCompound.setTag(par1Str, par2NBTBase);
676        }
677    
678        public boolean func_82835_x()
679        {
680            return this.getItem().func_82788_x();
681        }
682    
683        /**
684         * Return whether this stack is on an item frame.
685         */
686        public boolean isOnItemFrame()
687        {
688            return this.itemFrame != null;
689        }
690    
691        /**
692         * Set the item frame this stack is on.
693         */
694        public void setItemFrame(EntityItemFrame par1EntityItemFrame)
695        {
696            this.itemFrame = par1EntityItemFrame;
697        }
698    
699        /**
700         * Return the item frame this stack is on. Returns null if not on an item frame.
701         */
702        public EntityItemFrame getItemFrame()
703        {
704            return this.itemFrame;
705        }
706    
707        /**
708         * Get this stack's repair cost, or 0 if no repair cost is defined.
709         */
710        public int getRepairCost()
711        {
712            return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0;
713        }
714    
715        /**
716         * Set this stack's repair cost.
717         */
718        public void setRepairCost(int par1)
719        {
720            if (!this.hasTagCompound())
721            {
722                this.stackTagCompound = new NBTTagCompound();
723            }
724    
725            this.stackTagCompound.setInteger("RepairCost", par1);
726        }
727    }