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