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