    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    }