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        public ItemStack(Block par1Block)
030        {
031            this(par1Block, 1);
032        }
033    
034        public ItemStack(Block par1Block, int par2)
035        {
036            this(par1Block.blockID, par2, 0);
037        }
038    
039        public ItemStack(Block par1Block, int par2, int par3)
040        {
041            this(par1Block.blockID, par2, par3);
042        }
043    
044        public ItemStack(Item par1Item)
045        {
046            this(par1Item.shiftedIndex, 1, 0);
047        }
048    
049        public ItemStack(Item par1Item, int par2)
050        {
051            this(par1Item.shiftedIndex, par2, 0);
052        }
053    
054        public ItemStack(Item par1Item, int par2, int par3)
055        {
056            this(par1Item.shiftedIndex, par2, par3);
057        }
058    
059        public ItemStack(int par1, int par2, int par3)
060        {
061            this.stackSize = 0;
062            this.itemID = par1;
063            this.stackSize = par2;
064            this.itemDamage = par3;
065        }
066    
067        public static ItemStack loadItemStackFromNBT(NBTTagCompound par0NBTTagCompound)
068        {
069            ItemStack var1 = new ItemStack();
070            var1.readFromNBT(par0NBTTagCompound);
071            return var1.getItem() != null ? var1 : null;
072        }
073    
074        private ItemStack()
075        {
076            this.stackSize = 0;
077        }
078    
079        /**
080         * Remove the argument from the stack size. Return a new stack object with argument size.
081         */
082        public ItemStack splitStack(int par1)
083        {
084            ItemStack var2 = new ItemStack(this.itemID, par1, this.itemDamage);
085    
086            if (this.stackTagCompound != null)
087            {
088                var2.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
089            }
090    
091            this.stackSize -= par1;
092            return var2;
093        }
094    
095        /**
096         * Returns the object corresponding to the stack.
097         */
098        public Item getItem()
099        {
100            return Item.itemsList[this.itemID];
101        }
102    
103        @SideOnly(Side.CLIENT)
104    
105        /**
106         * Returns the icon index of the current stack.
107         */
108        public int getIconIndex()
109        {
110            return this.getItem().getIconIndex(this);
111        }
112    
113        public boolean tryPlaceItemIntoWorld(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5, int par6, float par7, float par8, float par9)
114        {
115            boolean var10 = this.getItem().onItemUse(this, par1EntityPlayer, par2World, par3, par4, par5, par6, par7, par8, par9);
116    
117            if (var10)
118            {
119                par1EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
120            }
121    
122            return var10;
123        }
124    
125        /**
126         * Returns the strength of the stack against a given block.
127         */
128        public float getStrVsBlock(Block par1Block)
129        {
130            return this.getItem().getStrVsBlock(this, par1Block);
131        }
132    
133        /**
134         * Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position
135         * where this item is. Args: world, player
136         */
137        public ItemStack useItemRightClick(World par1World, EntityPlayer par2EntityPlayer)
138        {
139            return this.getItem().onItemRightClick(this, par1World, par2EntityPlayer);
140        }
141    
142        public ItemStack onFoodEaten(World par1World, EntityPlayer par2EntityPlayer)
143        {
144            return this.getItem().onFoodEaten(this, par1World, par2EntityPlayer);
145        }
146    
147        /**
148         * Write the stack fields to a NBT object. Return the new NBT object.
149         */
150        public NBTTagCompound writeToNBT(NBTTagCompound par1NBTTagCompound)
151        {
152            par1NBTTagCompound.setShort("id", (short)this.itemID);
153            par1NBTTagCompound.setByte("Count", (byte)this.stackSize);
154            par1NBTTagCompound.setShort("Damage", (short)this.itemDamage);
155    
156            if (this.stackTagCompound != null)
157            {
158                par1NBTTagCompound.setTag("tag", this.stackTagCompound);
159            }
160    
161            return par1NBTTagCompound;
162        }
163    
164        /**
165         * Read the stack fields from a NBT object.
166         */
167        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
168        {
169            this.itemID = par1NBTTagCompound.getShort("id");
170            this.stackSize = par1NBTTagCompound.getByte("Count");
171            this.itemDamage = par1NBTTagCompound.getShort("Damage");
172    
173            if (par1NBTTagCompound.hasKey("tag"))
174            {
175                this.stackTagCompound = par1NBTTagCompound.getCompoundTag("tag");
176            }
177        }
178    
179        /**
180         * Returns maximum size of the stack.
181         */
182        public int getMaxStackSize()
183        {
184            return this.getItem().getItemStackLimit();
185        }
186    
187        /**
188         * Returns true if the ItemStack can hold 2 or more units of the item.
189         */
190        public boolean isStackable()
191        {
192            return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged());
193        }
194    
195        /**
196         * true if this itemStack is damageable
197         */
198        public boolean isItemStackDamageable()
199        {
200            return Item.itemsList[this.itemID].getMaxDamage() > 0;
201        }
202    
203        public boolean getHasSubtypes()
204        {
205            return Item.itemsList[this.itemID].getHasSubtypes();
206        }
207    
208        /**
209         * returns true when a damageable item is damaged
210         */
211        public boolean isItemDamaged()
212        {
213            return this.isItemStackDamageable() && this.itemDamage > 0;
214        }
215    
216        /**
217         * gets the damage of an itemstack, for displaying purposes
218         */
219        public int getItemDamageForDisplay()
220        {
221            return this.itemDamage;
222        }
223    
224        /**
225         * gets the damage of an itemstack
226         */
227        public int getItemDamage()
228        {
229            return this.itemDamage;
230        }
231    
232        /**
233         * Sets the item damage of the ItemStack.
234         */
235        public void setItemDamage(int par1)
236        {
237            this.itemDamage = par1;
238        }
239    
240        /**
241         * Returns the max damage an item in the stack can take.
242         */
243        public int getMaxDamage()
244        {
245            return Item.itemsList[this.itemID].getMaxDamage();
246        }
247    
248        /**
249         * Damages the item in the ItemStack
250         */
251        public void damageItem(int par1, EntityLiving par2EntityLiving)
252        {
253            if (this.isItemStackDamageable())
254            {
255                if (par1 > 0 && par2EntityLiving instanceof EntityPlayer)
256                {
257                    int var3 = EnchantmentHelper.getUnbreakingModifier(((EntityPlayer)par2EntityLiving).inventory);
258    
259                    if (var3 > 0 && par2EntityLiving.worldObj.rand.nextInt(var3 + 1) > 0)
260                    {
261                        return;
262                    }
263                }
264    
265                if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode)
266                {
267                    this.itemDamage += par1;
268                }
269    
270                if (this.itemDamage > this.getMaxDamage())
271                {
272                    par2EntityLiving.renderBrokenItemStack(this);
273    
274                    if (par2EntityLiving instanceof EntityPlayer)
275                    {
276                        ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1);
277                    }
278    
279                    --this.stackSize;
280    
281                    if (this.stackSize < 0)
282                    {
283                        this.stackSize = 0;
284                    }
285    
286                    this.itemDamage = 0;
287                }
288            }
289        }
290    
291        /**
292         * Calls the corresponding fct in di
293         */
294        public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer)
295        {
296            boolean var3 = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer);
297    
298            if (var3)
299            {
300                par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
301            }
302        }
303    
304        public void func_77941_a(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
305        {
306            boolean var7 = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer);
307    
308            if (var7)
309            {
310                par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
311            }
312        }
313    
314        /**
315         * Returns the damage against a given entity.
316         */
317        public int getDamageVsEntity(Entity par1Entity)
318        {
319            return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity);
320        }
321    
322        /**
323         * Checks if the itemStack object can harvest a specified block
324         */
325        public boolean canHarvestBlock(Block par1Block)
326        {
327            return Item.itemsList[this.itemID].canHarvestBlock(par1Block);
328        }
329    
330        public boolean interactWith(EntityLiving par1EntityLiving)
331        {
332            return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving);
333        }
334    
335        /**
336         * Returns a new stack with the same properties.
337         */
338        public ItemStack copy()
339        {
340            ItemStack var1 = new ItemStack(this.itemID, this.stackSize, this.itemDamage);
341    
342            if (this.stackTagCompound != null)
343            {
344                var1.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
345            }
346    
347            return var1;
348        }
349    
350        public static boolean func_77970_a(ItemStack par0ItemStack, ItemStack par1ItemStack)
351        {
352            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);
353        }
354    
355        /**
356         * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal
357         */
358        public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack)
359        {
360            return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false);
361        }
362    
363        /**
364         * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal
365         */
366        private boolean isItemStackEqual(ItemStack par1ItemStack)
367        {
368            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))));
369        }
370    
371        /**
372         * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are
373         * equal
374         */
375        public boolean isItemEqual(ItemStack par1ItemStack)
376        {
377            return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage;
378        }
379    
380        public String getItemName()
381        {
382            return Item.itemsList[this.itemID].getItemNameIS(this);
383        }
384    
385        /**
386         * Creates a copy of a ItemStack, a null parameters will return a null.
387         */
388        public static ItemStack copyItemStack(ItemStack par0ItemStack)
389        {
390            return par0ItemStack == null ? null : par0ItemStack.copy();
391        }
392    
393        public String toString()
394        {
395            return this.stackSize + "x" + Item.itemsList[this.itemID].getItemName() + "@" + this.itemDamage;
396        }
397    
398        /**
399         * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update
400         * maps.
401         */
402        public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4)
403        {
404            if (this.animationsToGo > 0)
405            {
406                --this.animationsToGo;
407            }
408    
409            Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4);
410        }
411    
412        public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3)
413        {
414            par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3);
415            Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer);
416        }
417    
418        public boolean isStackEqual(ItemStack par1ItemStack)
419        {
420            return this.itemID == par1ItemStack.itemID && this.stackSize == par1ItemStack.stackSize && this.itemDamage == par1ItemStack.itemDamage;
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        @SideOnly(Side.CLIENT)
471    
472        /**
473         * gets a list of strings representing the item name and successive extra data, eg Enchantments and potion effects
474         */
475        public List getItemNameandInformation()
476        {
477            ArrayList var1 = new ArrayList();
478            Item var2 = Item.itemsList[this.itemID];
479            var1.add(var2.getItemDisplayName(this));
480            var2.addInformation(this, var1);
481    
482            if (this.hasTagCompound())
483            {
484                NBTTagList var3 = this.getEnchantmentTagList();
485    
486                if (var3 != null)
487                {
488                    for (int var4 = 0; var4 < var3.tagCount(); ++var4)
489                    {
490                        short var5 = ((NBTTagCompound)var3.tagAt(var4)).getShort("id");
491                        short var6 = ((NBTTagCompound)var3.tagAt(var4)).getShort("lvl");
492    
493                        if (Enchantment.enchantmentsList[var5] != null)
494                        {
495                            var1.add(Enchantment.enchantmentsList[var5].getTranslatedName(var6));
496                        }
497                    }
498                }
499            }
500    
501            return var1;
502        }
503    
504        @SideOnly(Side.CLIENT)
505        public boolean hasEffect()
506        {
507            return this.getItem().hasEffect(this);
508        }
509    
510        @SideOnly(Side.CLIENT)
511        public EnumRarity getRarity()
512        {
513            return this.getItem().getRarity(this);
514        }
515    
516        /**
517         * True if it is a tool and has no enchantments to begin with
518         */
519        public boolean isItemEnchantable()
520        {
521            return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
522        }
523    
524        /**
525         * Adds an enchantment with a desired level on the ItemStack.
526         */
527        public void addEnchantment(Enchantment par1Enchantment, int par2)
528        {
529            if (this.stackTagCompound == null)
530            {
531                this.setTagCompound(new NBTTagCompound());
532            }
533    
534            if (!this.stackTagCompound.hasKey("ench"))
535            {
536                this.stackTagCompound.setTag("ench", new NBTTagList("ench"));
537            }
538    
539            NBTTagList var3 = (NBTTagList)this.stackTagCompound.getTag("ench");
540            NBTTagCompound var4 = new NBTTagCompound();
541            var4.setShort("id", (short)par1Enchantment.effectId);
542            var4.setShort("lvl", (short)((byte)par2));
543            var3.appendTag(var4);
544        }
545    
546        /**
547         * True if the item has enchantment data
548         */
549        public boolean isItemEnchanted()
550        {
551            return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench");
552        }
553    
554        @SideOnly(Side.CLIENT)
555        public void func_77983_a(String par1Str, NBTBase par2NBTBase)
556        {
557            if (this.stackTagCompound == null)
558            {
559                this.setTagCompound(new NBTTagCompound());
560            }
561    
562            this.stackTagCompound.setTag(par1Str, par2NBTBase);
563        }
564    }