    001package net.minecraft.entity.player;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import net.minecraft.block.Block;
    006import net.minecraft.entity.Entity;
    007import net.minecraft.inventory.IInventory;
    008import net.minecraft.item.Item;
    009import net.minecraft.item.ItemArmor;
    010import net.minecraft.item.ItemStack;
    011import net.minecraft.nbt.NBTTagCompound;
    012import net.minecraft.nbt.NBTTagList;
    013
    014public class InventoryPlayer implements IInventory
    015{
    016    /**
    017     * An array of 36 item stacks indicating the main player inventory (including the visible bar).
    018     */
    019    public ItemStack[] mainInventory = new ItemStack[36];
    020
    021    /** An array of 4 item stacks containing the currently worn armor pieces. */
    022    public ItemStack[] armorInventory = new ItemStack[4];
    023
    024    /** The index of the currently held item (0-8). */
    025    public int currentItem = 0;
    026    @SideOnly(Side.CLIENT)
    027
    028    /** The current ItemStack. */
    029    private ItemStack currentItemStack;
    030
    031    /** The player whose inventory this is. */
    032    public EntityPlayer player;
    033    private ItemStack itemStack;
    034
    035    /**
    036     * Set true whenever the inventory changes. Nothing sets it false so you will have to write your own code to check
    037     * it and reset the value.
    038     */
    039    public boolean inventoryChanged = false;
    040
    041    public InventoryPlayer(EntityPlayer par1EntityPlayer)
    042    {
    043        this.player = par1EntityPlayer;
    044    }
    045
    046    /**
    047     * Returns the item stack currently held by the player.
    048     */
    049    public ItemStack getCurrentItem()
    050    {
    051        return this.currentItem < 9 && this.currentItem >= 0 ? this.mainInventory[this.currentItem] : null;
    052    }
    053
    054    /**
    055     * Get the size of the player hotbar inventory
    056     */
    057    public static int getHotbarSize()
    058    {
    059        return 9;
    060    }
    061
    062    /**
    063     * Returns a slot index in main inventory containing a specific itemID
    064     */
    065    private int getInventorySlotContainItem(int par1)
    066    {
    067        for (int var2 = 0; var2 < this.mainInventory.length; ++var2)
    068        {
    069            if (this.mainInventory[var2] != null && this.mainInventory[var2].itemID == par1)
    070            {
    071                return var2;
    072            }
    073        }
    074
    075        return -1;
    076    }
    077
    078    @SideOnly(Side.CLIENT)
    079    private int getInventorySlotContainItemAndDamage(int par1, int par2)
    080    {
    081        for (int var3 = 0; var3 < this.mainInventory.length; ++var3)
    082        {
    083            if (this.mainInventory[var3] != null && this.mainInventory[var3].itemID == par1 && this.mainInventory[var3].getItemDamage() == par2)
    084            {
    085                return var3;
    086            }
    087        }
    088
    089        return -1;
    090    }
    091
    092    /**
    093     * stores an itemstack in the users inventory
    094     */
    095    private int storeItemStack(ItemStack par1ItemStack)
    096    {
    097        for (int var2 = 0; var2 < this.mainInventory.length; ++var2)
    098        {
    099            if (this.mainInventory[var2] != null && this.mainInventory[var2].itemID == par1ItemStack.itemID && this.mainInventory[var2].isStackable() && this.mainInventory[var2].stackSize < this.mainInventory[var2].getMaxStackSize() && this.mainInventory[var2].stackSize < this.getInventoryStackLimit() && (!this.mainInventory[var2].getHasSubtypes() || this.mainInventory[var2].getItemDamage() == par1ItemStack.getItemDamage()) && ItemStack.areItemStackTagsEqual(this.mainInventory[var2], par1ItemStack))
    100            {
    101                return var2;
    102            }
    103        }
    104
    105        return -1;
    106    }
    107
    108    /**
    109     * Returns the first item stack that is empty.
    110     */
    111    public int getFirstEmptyStack()
    112    {
    113        for (int var1 = 0; var1 < this.mainInventory.length; ++var1)
    114        {
    115            if (this.mainInventory[var1] == null)
    116            {
    117                return var1;
    118            }
    119        }
    120
    121        return -1;
    122    }
    123
    124    @SideOnly(Side.CLIENT)
    125
    126    /**
    127     * Sets a specific itemID as the current item being held (only if it exists on the hotbar)
    128     */
    129    public void setCurrentItem(int par1, int par2, boolean par3, boolean par4)
    130    {
    131        boolean var5 = true;
    132        this.currentItemStack = this.getCurrentItem();
    133        int var7;
    134
    135        if (par3)
    136        {
    137            var7 = this.getInventorySlotContainItemAndDamage(par1, par2);
    138        }
    139        else
    140        {
    141            var7 = this.getInventorySlotContainItem(par1);
    142        }
    143
    144        if (var7 >= 0 && var7 < 9)
    145        {
    146            this.currentItem = var7;
    147        }
    148        else
    149        {
    150            if (par4 && par1 > 0)
    151            {
    152                int var6 = this.getFirstEmptyStack();
    153
    154                if (var6 >= 0 && var6 < 9)
    155                {
    156                    this.currentItem = var6;
    157                }
    158
    159                this.func_70439_a(Item.itemsList[par1], par2);
    160            }
    161        }
    162    }
    163
    164    @SideOnly(Side.CLIENT)
    165
    166    /**
    167     * Switch the current item to the next one or the previous one
    168     */
    169    public void changeCurrentItem(int par1)
    170    {
    171        if (par1 > 0)
    172        {
    173            par1 = 1;
    174        }
    175
    176        if (par1 < 0)
    177        {
    178            par1 = -1;
    179        }
    180
    181        for (this.currentItem -= par1; this.currentItem < 0; this.currentItem += 9)
    182        {
    183            ;
    184        }
    185
    186        while (this.currentItem >= 9)
    187        {
    188            this.currentItem -= 9;
    189        }
    190    }
    191
    192    /**
    193     * Clear this player's inventory, using the specified ID and metadata as filters or -1 for no filter.
    194     */
    195    public int clearInventory(int par1, int par2)
    196    {
    197        int var3 = 0;
    198        int var4;
    199        ItemStack var5;
    200
    201        for (var4 = 0; var4 < this.mainInventory.length; ++var4)
    202        {
    203            var5 = this.mainInventory[var4];
    204
    205            if (var5 != null && (par1 <= -1 || var5.itemID == par1) && (par2 <= -1 || var5.getItemDamage() == par2))
    206            {
    207                var3 += var5.stackSize;
    208                this.mainInventory[var4] = null;
    209            }
    210        }
    211
    212        for (var4 = 0; var4 < this.armorInventory.length; ++var4)
    213        {
    214            var5 = this.armorInventory[var4];
    215
    216            if (var5 != null && (par1 <= -1 || var5.itemID == par1) && (par2 <= -1 || var5.getItemDamage() == par2))
    217            {
    218                var3 += var5.stackSize;
    219                this.armorInventory[var4] = null;
    220            }
    221        }
    222
    223        return var3;
    224    }
    225
    226    @SideOnly(Side.CLIENT)
    227    public void func_70439_a(Item par1Item, int par2)
    228    {
    229        if (par1Item != null)
    230        {
    231            int var3 = this.getInventorySlotContainItemAndDamage(par1Item.itemID, par2);
    232
    233            if (var3 >= 0)
    234            {
    235                this.mainInventory[var3] = this.mainInventory[this.currentItem];
    236            }
    237
    238            if (this.currentItemStack != null && this.currentItemStack.isItemEnchantable() && this.getInventorySlotContainItemAndDamage(this.currentItemStack.itemID, this.currentItemStack.getItemDamageForDisplay()) == this.currentItem)
    239            {
    240                return;
    241            }
    242
    243            this.mainInventory[this.currentItem] = new ItemStack(Item.itemsList[par1Item.itemID], 1, par2);
    244        }
    245    }
    246
    247    /**
    248     * This function stores as many items of an ItemStack as possible in a matching slot and returns the quantity of
    249     * left over items.
    250     */
    251    private int storePartialItemStack(ItemStack par1ItemStack)
    252    {
    253        int var2 = par1ItemStack.itemID;
    254        int var3 = par1ItemStack.stackSize;
    255        int var4;
    256
    257        if (par1ItemStack.getMaxStackSize() == 1)
    258        {
    259            var4 = this.getFirstEmptyStack();
    260
    261            if (var4 < 0)
    262            {
    263                return var3;
    264            }
    265            else
    266            {
    267                if (this.mainInventory[var4] == null)
    268                {
    269                    this.mainInventory[var4] = ItemStack.copyItemStack(par1ItemStack);
    270                }
    271
    272                return 0;
    273            }
    274        }
    275        else
    276        {
    277            var4 = this.storeItemStack(par1ItemStack);
    278
    279            if (var4 < 0)
    280            {
    281                var4 = this.getFirstEmptyStack();
    282            }
    283
    284            if (var4 < 0)
    285            {
    286                return var3;
    287            }
    288            else
    289            {
    290                if (this.mainInventory[var4] == null)
    291                {
    292                    this.mainInventory[var4] = new ItemStack(var2, 0, par1ItemStack.getItemDamage());
    293
    294                    if (par1ItemStack.hasTagCompound())
    295                    {
    296                        this.mainInventory[var4].setTagCompound((NBTTagCompound)par1ItemStack.getTagCompound().copy());
    297                    }
    298                }
    299
    300                int var5 = var3;
    301
    302                if (var3 > this.mainInventory[var4].getMaxStackSize() - this.mainInventory[var4].stackSize)
    303                {
    304                    var5 = this.mainInventory[var4].getMaxStackSize() - this.mainInventory[var4].stackSize;
    305                }
    306
    307                if (var5 > this.getInventoryStackLimit() - this.mainInventory[var4].stackSize)
    308                {
    309                    var5 = this.getInventoryStackLimit() - this.mainInventory[var4].stackSize;
    310                }
    311
    312                if (var5 == 0)
    313                {
    314                    return var3;
    315                }
    316                else
    317                {
    318                    var3 -= var5;
    319                    this.mainInventory[var4].stackSize += var5;
    320                    this.mainInventory[var4].animationsToGo = 5;
    321                    return var3;
    322                }
    323            }
    324        }
    325    }
    326
    327    /**
    328     * Decrement the number of animations remaining. Only called on client side. This is used to handle the animation of
    329     * receiving a block.
    330     */
    331    public void decrementAnimations()
    332    {
    333        for (int var1 = 0; var1 < this.mainInventory.length; ++var1)
    334        {
    335            if (this.mainInventory[var1] != null)
    336            {
    337                this.mainInventory[var1].updateAnimation(this.player.worldObj, this.player, var1, this.currentItem == var1);
    338            }
    339        }
    340
    341        for (int i = 0; i < this.armorInventory.length; i++)
    342        {
    343            if (this.armorInventory[i] != null)
    344            {
    345                this.armorInventory[i].getItem().onArmorTickUpdate(this.player.worldObj, this.player, this.armorInventory[i]);
    346            }
    347        }
    348    }
    349
    350    /**
    351     * removed one item of specified itemID from inventory (if it is in a stack, the stack size will reduce with 1)
    352     */
    353    public boolean consumeInventoryItem(int par1)
    354    {
    355        int var2 = this.getInventorySlotContainItem(par1);
    356
    357        if (var2 < 0)
    358        {
    359            return false;
    360        }
    361        else
    362        {
    363            if (--this.mainInventory[var2].stackSize <= 0)
    364            {
    365                this.mainInventory[var2] = null;
    366            }
    367
    368            return true;
    369        }
    370    }
    371
    372    /**
    373     * Get if a specifiied item id is inside the inventory.
    374     */
    375    public boolean hasItem(int par1)
    376    {
    377        int var2 = this.getInventorySlotContainItem(par1);
    378        return var2 >= 0;
    379    }
    380
    381    /**
    382     * Adds the item stack to the inventory, returns false if it is impossible.
    383     */
    384    public boolean addItemStackToInventory(ItemStack par1ItemStack)
    385    {
    386        int var2;
    387
    388        if (par1ItemStack.isItemDamaged())
    389        {
    390            var2 = this.getFirstEmptyStack();
    391
    392            if (var2 >= 0)
    393            {
    394                this.mainInventory[var2] = ItemStack.copyItemStack(par1ItemStack);
    395                this.mainInventory[var2].animationsToGo = 5;
    396                par1ItemStack.stackSize = 0;
    397                return true;
    398            }
    399            else if (this.player.capabilities.isCreativeMode)
    400            {
    401                par1ItemStack.stackSize = 0;
    402                return true;
    403            }
    404            else
    405            {
    406                return false;
    407            }
    408        }
    409        else
    410        {
    411            do
    412            {
    413                var2 = par1ItemStack.stackSize;
    414                par1ItemStack.stackSize = this.storePartialItemStack(par1ItemStack);
    415            }
    416            while (par1ItemStack.stackSize > 0 && par1ItemStack.stackSize < var2);
    417
    418            if (par1ItemStack.stackSize == var2 && this.player.capabilities.isCreativeMode)
    419            {
    420                par1ItemStack.stackSize = 0;
    421                return true;
    422            }
    423            else
    424            {
    425                return par1ItemStack.stackSize < var2;
    426            }
    427        }
    428    }
    429
    430    /**
    431     * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
    432     * new stack.
    433     */
    434    public ItemStack decrStackSize(int par1, int par2)
    435    {
    436        ItemStack[] var3 = this.mainInventory;
    437
    438        if (par1 >= this.mainInventory.length)
    439        {
    440            var3 = this.armorInventory;
    441            par1 -= this.mainInventory.length;
    442        }
    443
    444        if (var3[par1] != null)
    445        {
    446            ItemStack var4;
    447
    448            if (var3[par1].stackSize <= par2)
    449            {
    450                var4 = var3[par1];
    451                var3[par1] = null;
    452                return var4;
    453            }
    454            else
    455            {
    456                var4 = var3[par1].splitStack(par2);
    457
    458                if (var3[par1].stackSize == 0)
    459                {
    460                    var3[par1] = null;
    461                }
    462
    463                return var4;
    464            }
    465        }
    466        else
    467        {
    468            return null;
    469        }
    470    }
    471
    472    /**
    473     * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
    474     * like when you close a workbench GUI.
    475     */
    476    public ItemStack getStackInSlotOnClosing(int par1)
    477    {
    478        ItemStack[] var2 = this.mainInventory;
    479
    480        if (par1 >= this.mainInventory.length)
    481        {
    482            var2 = this.armorInventory;
    483            par1 -= this.mainInventory.length;
    484        }
    485
    486        if (var2[par1] != null)
    487        {
    488            ItemStack var3 = var2[par1];
    489            var2[par1] = null;
    490            return var3;
    491        }
    492        else
    493        {
    494            return null;
    495        }
    496    }
    497
    498    /**
    499     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
    500     */
    501    public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
    502    {
    503        ItemStack[] var3 = this.mainInventory;
    504
    505        if (par1 >= var3.length)
    506        {
    507            par1 -= var3.length;
    508            var3 = this.armorInventory;
    509        }
    510
    511        var3[par1] = par2ItemStack;
    512    }
    513
    514    /**
    515     * Gets the strength of the current item (tool) against the specified block, 1.0f if not holding anything.
    516     */
    517    public float getStrVsBlock(Block par1Block)
    518    {
    519        float var2 = 1.0F;
    520
    521        if (this.mainInventory[this.currentItem] != null)
    522        {
    523            var2 *= this.mainInventory[this.currentItem].getStrVsBlock(par1Block);
    524        }
    525
    526        return var2;
    527    }
    528
    529    /**
    530     * Writes the inventory out as a list of compound tags. This is where the slot indices are used (+100 for armor, +80
    531     * for crafting).
    532     */
    533    public NBTTagList writeToNBT(NBTTagList par1NBTTagList)
    534    {
    535        int var2;
    536        NBTTagCompound var3;
    537
    538        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
    539        {
    540            if (this.mainInventory[var2] != null)
    541            {
    542                var3 = new NBTTagCompound();
    543                var3.setByte("Slot", (byte)var2);
    544                this.mainInventory[var2].writeToNBT(var3);
    545                par1NBTTagList.appendTag(var3);
    546            }
    547        }
    548
    549        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
    550        {
    551            if (this.armorInventory[var2] != null)
    552            {
    553                var3 = new NBTTagCompound();
    554                var3.setByte("Slot", (byte)(var2 + 100));
    555                this.armorInventory[var2].writeToNBT(var3);
    556                par1NBTTagList.appendTag(var3);
    557            }
    558        }
    559
    560        return par1NBTTagList;
    561    }
    562
    563    /**
    564     * Reads from the given tag list and fills the slots in the inventory with the correct items.
    565     */
    566    public void readFromNBT(NBTTagList par1NBTTagList)
    567    {
    568        this.mainInventory = new ItemStack[36];
    569        this.armorInventory = new ItemStack[4];
    570
    571        for (int var2 = 0; var2 < par1NBTTagList.tagCount(); ++var2)
    572        {
    573            NBTTagCompound var3 = (NBTTagCompound)par1NBTTagList.tagAt(var2);
    574            int var4 = var3.getByte("Slot") & 255;
    575            ItemStack var5 = ItemStack.loadItemStackFromNBT(var3);
    576
    577            if (var5 != null)
    578            {
    579                if (var4 >= 0 && var4 < this.mainInventory.length)
    580                {
    581                    this.mainInventory[var4] = var5;
    582                }
    583
    584                if (var4 >= 100 && var4 < this.armorInventory.length + 100)
    585                {
    586                    this.armorInventory[var4 - 100] = var5;
    587                }
    588            }
    589        }
    590    }
    591
    592    /**
    593     * Returns the number of slots in the inventory.
    594     */
    595    public int getSizeInventory()
    596    {
    597        return this.mainInventory.length + 4;
    598    }
    599
    600    /**
    601     * Returns the stack in slot i
    602     */
    603    public ItemStack getStackInSlot(int par1)
    604    {
    605        ItemStack[] var2 = this.mainInventory;
    606
    607        if (par1 >= var2.length)
    608        {
    609            par1 -= var2.length;
    610            var2 = this.armorInventory;
    611        }
    612
    613        return var2[par1];
    614    }
    615
    616    /**
    617     * Returns the name of the inventory.
    618     */
    619    public String getInvName()
    620    {
    621        return "container.inventory";
    622    }
    623
    624    /**
    625     * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
    626     * this more of a set than a get?*
    627     */
    628    public int getInventoryStackLimit()
    629    {
    630        return 64;
    631    }
    632
    633    /**
    634     * Return damage vs an entity done by the current held weapon, or 1 if nothing is held
    635     */
    636    public int getDamageVsEntity(Entity par1Entity)
    637    {
    638        ItemStack var2 = this.getStackInSlot(this.currentItem);
    639        return var2 != null ? var2.getDamageVsEntity(par1Entity) : 1;
    640    }
    641
    642    /**
    643     * Returns whether the current item (tool) can harvest from the specified block (actually get a result).
    644     */
    645    public boolean canHarvestBlock(Block par1Block)
    646    {
    647        if (par1Block.blockMaterial.isToolNotRequired())
    648        {
    649            return true;
    650        }
    651        else
    652        {
    653            ItemStack var2 = this.getStackInSlot(this.currentItem);
    654            return var2 != null ? var2.canHarvestBlock(par1Block) : false;
    655        }
    656    }
    657
    658    /**
    659     * returns a player armor item (as itemstack) contained in specified armor slot.
    660     */
    661    public ItemStack armorItemInSlot(int par1)
    662    {
    663        return this.armorInventory[par1];
    664    }
    665
    666    /**
    667     * Based on the damage values and maximum damage values of each armor item, returns the current armor value.
    668     */
    669    public int getTotalArmorValue()
    670    {
    671        int var1 = 0;
    672
    673        for (int var2 = 0; var2 < this.armorInventory.length; ++var2)
    674        {
    675            if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor)
    676            {
    677                int var3 = ((ItemArmor)this.armorInventory[var2].getItem()).damageReduceAmount;
    678                var1 += var3;
    679            }
    680        }
    681
    682        return var1;
    683    }
    684
    685    /**
    686     * Damages armor in each slot by the specified amount.
    687     */
    688    public void damageArmor(int par1)
    689    {
    690        par1 /= 4;
    691
    692        if (par1 < 1)
    693        {
    694            par1 = 1;
    695        }
    696
    697        for (int var2 = 0; var2 < this.armorInventory.length; ++var2)
    698        {
    699            if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor)
    700            {
    701                this.armorInventory[var2].damageItem(par1, this.player);
    702
    703                if (this.armorInventory[var2].stackSize == 0)
    704                {
    705                    this.armorInventory[var2] = null;
    706                }
    707            }
    708        }
    709    }
    710
    711    /**
    712     * Drop all armor and main inventory items.
    713     */
    714    public void dropAllItems()
    715    {
    716        int var1;
    717
    718        for (var1 = 0; var1 < this.mainInventory.length; ++var1)
    719        {
    720            if (this.mainInventory[var1] != null)
    721            {
    722                this.player.dropPlayerItemWithRandomChoice(this.mainInventory[var1], true);
    723                this.mainInventory[var1] = null;
    724            }
    725        }
    726
    727        for (var1 = 0; var1 < this.armorInventory.length; ++var1)
    728        {
    729            if (this.armorInventory[var1] != null)
    730            {
    731                this.player.dropPlayerItemWithRandomChoice(this.armorInventory[var1], true);
    732                this.armorInventory[var1] = null;
    733            }
    734        }
    735    }
    736
    737    /**
    738     * Called when an the contents of an Inventory change, usually
    739     */
    740    public void onInventoryChanged()
    741    {
    742        this.inventoryChanged = true;
    743    }
    744
    745    public void setItemStack(ItemStack par1ItemStack)
    746    {
    747        this.itemStack = par1ItemStack;
    748    }
    749
    750    public ItemStack getItemStack()
    751    {
    752        return this.itemStack;
    753    }
    754
    755    /**
    756     * Do not make give this method the name canInteractWith because it clashes with Container
    757     */
    758    public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
    759    {
    760        return this.player.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this.player) <= 64.0D;
    761    }
    762
    763    /**
    764     * Returns true if the specified ItemStack exists in the inventory.
    765     */
    766    public boolean hasItemStack(ItemStack par1ItemStack)
    767    {
    768        int var2;
    769
    770        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
    771        {
    772            if (this.armorInventory[var2] != null && this.armorInventory[var2].isItemEqual(par1ItemStack))
    773            {
    774                return true;
    775            }
    776        }
    777
    778        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
    779        {
    780            if (this.mainInventory[var2] != null && this.mainInventory[var2].isItemEqual(par1ItemStack))
    781            {
    782                return true;
    783            }
    784        }
    785
    786        return false;
    787    }
    788
    789    public void openChest() {}
    790
    791    public void closeChest() {}
    792
    793    /**
    794     * Copy the ItemStack contents from another InventoryPlayer instance
    795     */
    796    public void copyInventory(InventoryPlayer par1InventoryPlayer)
    797    {
    798        int var2;
    799
    800        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
    801        {
    802            this.mainInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.mainInventory[var2]);
    803        }
    804
    805        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
    806        {
    807            this.armorInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.armorInventory[var2]);
    808        }
    809
    810        this.currentItem = par1InventoryPlayer.currentItem;
    811    }
    812}