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