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