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
342    /**
343     * removed one item of specified itemID from inventory (if it is in a stack, the stack size will reduce with 1)
344     */
345    public boolean consumeInventoryItem(int par1)
346    {
347        int var2 = this.getInventorySlotContainItem(par1);
348
349        if (var2 < 0)
350        {
351            return false;
352        }
353        else
354        {
355            if (--this.mainInventory[var2].stackSize <= 0)
356            {
357                this.mainInventory[var2] = null;
358            }
359
360            return true;
361        }
362    }
363
364    /**
365     * Get if a specifiied item id is inside the inventory.
366     */
367    public boolean hasItem(int par1)
368    {
369        int var2 = this.getInventorySlotContainItem(par1);
370        return var2 >= 0;
371    }
372
373    /**
374     * Adds the item stack to the inventory, returns false if it is impossible.
375     */
376    public boolean addItemStackToInventory(ItemStack par1ItemStack)
377    {
378        int var2;
379
380        if (par1ItemStack.isItemDamaged())
381        {
382            var2 = this.getFirstEmptyStack();
383
384            if (var2 >= 0)
385            {
386                this.mainInventory[var2] = ItemStack.copyItemStack(par1ItemStack);
387                this.mainInventory[var2].animationsToGo = 5;
388                par1ItemStack.stackSize = 0;
389                return true;
390            }
391            else if (this.player.capabilities.isCreativeMode)
392            {
393                par1ItemStack.stackSize = 0;
394                return true;
395            }
396            else
397            {
398                return false;
399            }
400        }
401        else
402        {
403            do
404            {
405                var2 = par1ItemStack.stackSize;
406                par1ItemStack.stackSize = this.storePartialItemStack(par1ItemStack);
407            }
408            while (par1ItemStack.stackSize > 0 && par1ItemStack.stackSize < var2);
409
410            if (par1ItemStack.stackSize == var2 && this.player.capabilities.isCreativeMode)
411            {
412                par1ItemStack.stackSize = 0;
413                return true;
414            }
415            else
416            {
417                return par1ItemStack.stackSize < var2;
418            }
419        }
420    }
421
422    /**
423     * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
424     * new stack.
425     */
426    public ItemStack decrStackSize(int par1, int par2)
427    {
428        ItemStack[] var3 = this.mainInventory;
429
430        if (par1 >= this.mainInventory.length)
431        {
432            var3 = this.armorInventory;
433            par1 -= this.mainInventory.length;
434        }
435
436        if (var3[par1] != null)
437        {
438            ItemStack var4;
439
440            if (var3[par1].stackSize <= par2)
441            {
442                var4 = var3[par1];
443                var3[par1] = null;
444                return var4;
445            }
446            else
447            {
448                var4 = var3[par1].splitStack(par2);
449
450                if (var3[par1].stackSize == 0)
451                {
452                    var3[par1] = null;
453                }
454
455                return var4;
456            }
457        }
458        else
459        {
460            return null;
461        }
462    }
463
464    /**
465     * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
466     * like when you close a workbench GUI.
467     */
468    public ItemStack getStackInSlotOnClosing(int par1)
469    {
470        ItemStack[] var2 = this.mainInventory;
471
472        if (par1 >= this.mainInventory.length)
473        {
474            var2 = this.armorInventory;
475            par1 -= this.mainInventory.length;
476        }
477
478        if (var2[par1] != null)
479        {
480            ItemStack var3 = var2[par1];
481            var2[par1] = null;
482            return var3;
483        }
484        else
485        {
486            return null;
487        }
488    }
489
490    /**
491     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
492     */
493    public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
494    {
495        ItemStack[] var3 = this.mainInventory;
496
497        if (par1 >= var3.length)
498        {
499            par1 -= var3.length;
500            var3 = this.armorInventory;
501        }
502
503        var3[par1] = par2ItemStack;
504    }
505
506    /**
507     * Gets the strength of the current item (tool) against the specified block, 1.0f if not holding anything.
508     */
509    public float getStrVsBlock(Block par1Block)
510    {
511        float var2 = 1.0F;
512
513        if (this.mainInventory[this.currentItem] != null)
514        {
515            var2 *= this.mainInventory[this.currentItem].getStrVsBlock(par1Block);
516        }
517
518        return var2;
519    }
520
521    /**
522     * Writes the inventory out as a list of compound tags. This is where the slot indices are used (+100 for armor, +80
523     * for crafting).
524     */
525    public NBTTagList writeToNBT(NBTTagList par1NBTTagList)
526    {
527        int var2;
528        NBTTagCompound var3;
529
530        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
531        {
532            if (this.mainInventory[var2] != null)
533            {
534                var3 = new NBTTagCompound();
535                var3.setByte("Slot", (byte)var2);
536                this.mainInventory[var2].writeToNBT(var3);
537                par1NBTTagList.appendTag(var3);
538            }
539        }
540
541        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
542        {
543            if (this.armorInventory[var2] != null)
544            {
545                var3 = new NBTTagCompound();
546                var3.setByte("Slot", (byte)(var2 + 100));
547                this.armorInventory[var2].writeToNBT(var3);
548                par1NBTTagList.appendTag(var3);
549            }
550        }
551
552        return par1NBTTagList;
553    }
554
555    /**
556     * Reads from the given tag list and fills the slots in the inventory with the correct items.
557     */
558    public void readFromNBT(NBTTagList par1NBTTagList)
559    {
560        this.mainInventory = new ItemStack[36];
561        this.armorInventory = new ItemStack[4];
562
563        for (int var2 = 0; var2 < par1NBTTagList.tagCount(); ++var2)
564        {
565            NBTTagCompound var3 = (NBTTagCompound)par1NBTTagList.tagAt(var2);
566            int var4 = var3.getByte("Slot") & 255;
567            ItemStack var5 = ItemStack.loadItemStackFromNBT(var3);
568
569            if (var5 != null)
570            {
571                if (var4 >= 0 && var4 < this.mainInventory.length)
572                {
573                    this.mainInventory[var4] = var5;
574                }
575
576                if (var4 >= 100 && var4 < this.armorInventory.length + 100)
577                {
578                    this.armorInventory[var4 - 100] = var5;
579                }
580            }
581        }
582    }
583
584    /**
585     * Returns the number of slots in the inventory.
586     */
587    public int getSizeInventory()
588    {
589        return this.mainInventory.length + 4;
590    }
591
592    /**
593     * Returns the stack in slot i
594     */
595    public ItemStack getStackInSlot(int par1)
596    {
597        ItemStack[] var2 = this.mainInventory;
598
599        if (par1 >= var2.length)
600        {
601            par1 -= var2.length;
602            var2 = this.armorInventory;
603        }
604
605        return var2[par1];
606    }
607
608    /**
609     * Returns the name of the inventory.
610     */
611    public String getInvName()
612    {
613        return "container.inventory";
614    }
615
616    /**
617     * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
618     * this more of a set than a get?*
619     */
620    public int getInventoryStackLimit()
621    {
622        return 64;
623    }
624
625    /**
626     * Return damage vs an entity done by the current held weapon, or 1 if nothing is held
627     */
628    public int getDamageVsEntity(Entity par1Entity)
629    {
630        ItemStack var2 = this.getStackInSlot(this.currentItem);
631        return var2 != null ? var2.getDamageVsEntity(par1Entity) : 1;
632    }
633
634    /**
635     * Returns whether the current item (tool) can harvest from the specified block (actually get a result).
636     */
637    public boolean canHarvestBlock(Block par1Block)
638    {
639        if (par1Block.blockMaterial.isToolNotRequired())
640        {
641            return true;
642        }
643        else
644        {
645            ItemStack var2 = this.getStackInSlot(this.currentItem);
646            return var2 != null ? var2.canHarvestBlock(par1Block) : false;
647        }
648    }
649
650    /**
651     * returns a player armor item (as itemstack) contained in specified armor slot.
652     */
653    public ItemStack armorItemInSlot(int par1)
654    {
655        return this.armorInventory[par1];
656    }
657
658    /**
659     * Based on the damage values and maximum damage values of each armor item, returns the current armor value.
660     */
661    public int getTotalArmorValue()
662    {
663        int var1 = 0;
664
665        for (int var2 = 0; var2 < this.armorInventory.length; ++var2)
666        {
667            if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor)
668            {
669                int var3 = ((ItemArmor)this.armorInventory[var2].getItem()).damageReduceAmount;
670                var1 += var3;
671            }
672        }
673
674        return var1;
675    }
676
677    /**
678     * Damages armor in each slot by the specified amount.
679     */
680    public void damageArmor(int par1)
681    {
682        par1 /= 4;
683
684        if (par1 < 1)
685        {
686            par1 = 1;
687        }
688
689        for (int var2 = 0; var2 < this.armorInventory.length; ++var2)
690        {
691            if (this.armorInventory[var2] != null && this.armorInventory[var2].getItem() instanceof ItemArmor)
692            {
693                this.armorInventory[var2].damageItem(par1, this.player);
694
695                if (this.armorInventory[var2].stackSize == 0)
696                {
697                    this.armorInventory[var2] = null;
698                }
699            }
700        }
701    }
702
703    /**
704     * Drop all armor and main inventory items.
705     */
706    public void dropAllItems()
707    {
708        int var1;
709
710        for (var1 = 0; var1 < this.mainInventory.length; ++var1)
711        {
712            if (this.mainInventory[var1] != null)
713            {
714                this.player.dropPlayerItemWithRandomChoice(this.mainInventory[var1], true);
715                this.mainInventory[var1] = null;
716            }
717        }
718
719        for (var1 = 0; var1 < this.armorInventory.length; ++var1)
720        {
721            if (this.armorInventory[var1] != null)
722            {
723                this.player.dropPlayerItemWithRandomChoice(this.armorInventory[var1], true);
724                this.armorInventory[var1] = null;
725            }
726        }
727    }
728
729    /**
730     * Called when an the contents of an Inventory change, usually
731     */
732    public void onInventoryChanged()
733    {
734        this.inventoryChanged = true;
735    }
736
737    public void setItemStack(ItemStack par1ItemStack)
738    {
739        this.itemStack = par1ItemStack;
740    }
741
742    public ItemStack getItemStack()
743    {
744        return this.itemStack;
745    }
746
747    /**
748     * Do not make give this method the name canInteractWith because it clashes with Container
749     */
750    public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
751    {
752        return this.player.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this.player) <= 64.0D;
753    }
754
755    /**
756     * Returns true if the specified ItemStack exists in the inventory.
757     */
758    public boolean hasItemStack(ItemStack par1ItemStack)
759    {
760        int var2;
761
762        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
763        {
764            if (this.armorInventory[var2] != null && this.armorInventory[var2].isItemEqual(par1ItemStack))
765            {
766                return true;
767            }
768        }
769
770        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
771        {
772            if (this.mainInventory[var2] != null && this.mainInventory[var2].isItemEqual(par1ItemStack))
773            {
774                return true;
775            }
776        }
777
778        return false;
779    }
780
781    public void openChest() {}
782
783    public void closeChest() {}
784
785    /**
786     * Copy the ItemStack contents from another InventoryPlayer instance
787     */
788    public void copyInventory(InventoryPlayer par1InventoryPlayer)
789    {
790        int var2;
791
792        for (var2 = 0; var2 < this.mainInventory.length; ++var2)
793        {
794            this.mainInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.mainInventory[var2]);
795        }
796
797        for (var2 = 0; var2 < this.armorInventory.length; ++var2)
798        {
799            this.armorInventory[var2] = ItemStack.copyItemStack(par1InventoryPlayer.armorInventory[var2]);
800        }
801
802        this.currentItem = par1InventoryPlayer.currentItem;
803    }
804}