    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    }