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}