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