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