001    package net.minecraft.entity.player;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.SideOnly;
005    import net.minecraft.block.Block;
006    import net.minecraft.entity.Entity;
007    import net.minecraft.inventory.IInventory;
008    import net.minecraft.item.Item;
009    import net.minecraft.item.ItemArmor;
010    import net.minecraft.item.ItemStack;
011    import net.minecraft.nbt.NBTTagCompound;
012    import net.minecraft.nbt.NBTTagList;
013    
014    public 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    }