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