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 }