001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.ArrayList;
006 import java.util.List;
007
008 public final class ItemStack
009 {
010 /** Size of the stack. */
011 public int stackSize;
012
013 /**
014 * Number of animation frames to go when receiving an item (by walking into it, for example).
015 */
016 public int animationsToGo;
017
018 /** ID of the item. */
019 public int itemID;
020
021 /**
022 * A NBTTagMap containing data about an ItemStack. Can only be used for non stackable items
023 */
024 public NBTTagCompound stackTagCompound;
025
026 /** Damage dealt to the item or number of use. Raise when using items. */
027 private int itemDamage;
028
029 /** Item frame this stack is on, or null if not on an item frame. */
030 private EntityItemFrame itemFrame;
031
032 public ItemStack(Block par1Block)
033 {
034 this(par1Block, 1);
035 }
036
037 public ItemStack(Block par1Block, int par2)
038 {
039 this(par1Block.blockID, par2, 0);
040 }
041
042 public ItemStack(Block par1Block, int par2, int par3)
043 {
044 this(par1Block.blockID, par2, par3);
045 }
046
047 public ItemStack(Item par1Item)
048 {
049 this(par1Item.shiftedIndex, 1, 0);
050 }
051
052 public ItemStack(Item par1Item, int par2)
053 {
054 this(par1Item.shiftedIndex, par2, 0);
055 }
056
057 public ItemStack(Item par1Item, int par2, int par3)
058 {
059 this(par1Item.shiftedIndex, par2, par3);
060 }
061
062 public ItemStack(int par1, int par2, int par3)
063 {
064 this.stackSize = 0;
065 this.itemFrame = null;
066 this.itemID = par1;
067 this.stackSize = par2;
068 this.itemDamage = par3;
069 }
070
071 public static ItemStack loadItemStackFromNBT(NBTTagCompound par0NBTTagCompound)
072 {
073 ItemStack var1 = new ItemStack();
074 var1.readFromNBT(par0NBTTagCompound);
075 return var1.getItem() != null ? var1 : null;
076 }
077
078 private ItemStack()
079 {
080 this.stackSize = 0;
081 this.itemFrame = null;
082 }
083
084 /**
085 * Remove the argument from the stack size. Return a new stack object with argument size.
086 */
087 public ItemStack splitStack(int par1)
088 {
089 ItemStack var2 = new ItemStack(this.itemID, par1, this.itemDamage);
090
091 if (this.stackTagCompound != null)
092 {
093 var2.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
094 }
095
096 this.stackSize -= par1;
097 return var2;
098 }
099
100 /**
101 * Returns the object corresponding to the stack.
102 */
103 public Item getItem()
104 {
105 return Item.itemsList[this.itemID];
106 }
107
108 @SideOnly(Side.CLIENT)
109
110 /**
111 * Returns the icon index of the current stack.
112 */
113 public int getIconIndex()
114 {
115 return this.getItem().getIconIndex(this);
116 }
117
118 public boolean tryPlaceItemIntoWorld(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5, int par6, float par7, float par8, float par9)
119 {
120 boolean var10 = this.getItem().onItemUse(this, par1EntityPlayer, par2World, par3, par4, par5, par6, par7, par8, par9);
121
122 if (var10)
123 {
124 par1EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
125 }
126
127 return var10;
128 }
129
130 /**
131 * Returns the strength of the stack against a given block.
132 */
133 public float getStrVsBlock(Block par1Block)
134 {
135 return this.getItem().getStrVsBlock(this, par1Block);
136 }
137
138 /**
139 * Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position
140 * where this item is. Args: world, player
141 */
142 public ItemStack useItemRightClick(World par1World, EntityPlayer par2EntityPlayer)
143 {
144 return this.getItem().onItemRightClick(this, par1World, par2EntityPlayer);
145 }
146
147 public ItemStack onFoodEaten(World par1World, EntityPlayer par2EntityPlayer)
148 {
149 return this.getItem().onFoodEaten(this, par1World, par2EntityPlayer);
150 }
151
152 /**
153 * Write the stack fields to a NBT object. Return the new NBT object.
154 */
155 public NBTTagCompound writeToNBT(NBTTagCompound par1NBTTagCompound)
156 {
157 par1NBTTagCompound.setShort("id", (short)this.itemID);
158 par1NBTTagCompound.setByte("Count", (byte)this.stackSize);
159 par1NBTTagCompound.setShort("Damage", (short)this.itemDamage);
160
161 if (this.stackTagCompound != null)
162 {
163 par1NBTTagCompound.setTag("tag", this.stackTagCompound);
164 }
165
166 return par1NBTTagCompound;
167 }
168
169 /**
170 * Read the stack fields from a NBT object.
171 */
172 public void readFromNBT(NBTTagCompound par1NBTTagCompound)
173 {
174 this.itemID = par1NBTTagCompound.getShort("id");
175 this.stackSize = par1NBTTagCompound.getByte("Count");
176 this.itemDamage = par1NBTTagCompound.getShort("Damage");
177
178 if (par1NBTTagCompound.hasKey("tag"))
179 {
180 this.stackTagCompound = par1NBTTagCompound.getCompoundTag("tag");
181 }
182 }
183
184 /**
185 * Returns maximum size of the stack.
186 */
187 public int getMaxStackSize()
188 {
189 return this.getItem().getItemStackLimit();
190 }
191
192 /**
193 * Returns true if the ItemStack can hold 2 or more units of the item.
194 */
195 public boolean isStackable()
196 {
197 return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged());
198 }
199
200 /**
201 * true if this itemStack is damageable
202 */
203 public boolean isItemStackDamageable()
204 {
205 return Item.itemsList[this.itemID].getMaxDamage() > 0;
206 }
207
208 public boolean getHasSubtypes()
209 {
210 return Item.itemsList[this.itemID].getHasSubtypes();
211 }
212
213 /**
214 * returns true when a damageable item is damaged
215 */
216 public boolean isItemDamaged()
217 {
218 return this.isItemStackDamageable() && this.itemDamage > 0;
219 }
220
221 /**
222 * gets the damage of an itemstack, for displaying purposes
223 */
224 public int getItemDamageForDisplay()
225 {
226 return this.itemDamage;
227 }
228
229 /**
230 * gets the damage of an itemstack
231 */
232 public int getItemDamage()
233 {
234 return this.itemDamage;
235 }
236
237 /**
238 * Sets the item damage of the ItemStack.
239 */
240 public void setItemDamage(int par1)
241 {
242 this.itemDamage = par1;
243 }
244
245 /**
246 * Returns the max damage an item in the stack can take.
247 */
248 public int getMaxDamage()
249 {
250 return Item.itemsList[this.itemID].getMaxDamage();
251 }
252
253 /**
254 * Damages the item in the ItemStack
255 */
256 public void damageItem(int par1, EntityLiving par2EntityLiving)
257 {
258 if (this.isItemStackDamageable())
259 {
260 if (par1 > 0 && par2EntityLiving instanceof EntityPlayer)
261 {
262 int var3 = EnchantmentHelper.getUnbreakingModifier(par2EntityLiving);
263
264 if (var3 > 0 && par2EntityLiving.worldObj.rand.nextInt(var3 + 1) > 0)
265 {
266 return;
267 }
268 }
269
270 if (!(par2EntityLiving instanceof EntityPlayer) || !((EntityPlayer)par2EntityLiving).capabilities.isCreativeMode)
271 {
272 this.itemDamage += par1;
273 }
274
275 if (this.itemDamage > this.getMaxDamage())
276 {
277 par2EntityLiving.renderBrokenItemStack(this);
278
279 if (par2EntityLiving instanceof EntityPlayer)
280 {
281 ((EntityPlayer)par2EntityLiving).addStat(StatList.objectBreakStats[this.itemID], 1);
282 }
283
284 --this.stackSize;
285
286 if (this.stackSize < 0)
287 {
288 this.stackSize = 0;
289 }
290
291 this.itemDamage = 0;
292 }
293 }
294 }
295
296 /**
297 * Calls the corresponding fct in di
298 */
299 public void hitEntity(EntityLiving par1EntityLiving, EntityPlayer par2EntityPlayer)
300 {
301 boolean var3 = Item.itemsList[this.itemID].hitEntity(this, par1EntityLiving, par2EntityPlayer);
302
303 if (var3)
304 {
305 par2EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
306 }
307 }
308
309 public void onBlockDestroyed(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer)
310 {
311 boolean var7 = Item.itemsList[this.itemID].onBlockDestroyed(this, par1World, par2, par3, par4, par5, par6EntityPlayer);
312
313 if (var7)
314 {
315 par6EntityPlayer.addStat(StatList.objectUseStats[this.itemID], 1);
316 }
317 }
318
319 /**
320 * Returns the damage against a given entity.
321 */
322 public int getDamageVsEntity(Entity par1Entity)
323 {
324 return Item.itemsList[this.itemID].getDamageVsEntity(par1Entity);
325 }
326
327 /**
328 * Checks if the itemStack object can harvest a specified block
329 */
330 public boolean canHarvestBlock(Block par1Block)
331 {
332 return Item.itemsList[this.itemID].canHarvestBlock(par1Block);
333 }
334
335 public boolean interactWith(EntityLiving par1EntityLiving)
336 {
337 return Item.itemsList[this.itemID].itemInteractionForEntity(this, par1EntityLiving);
338 }
339
340 /**
341 * Returns a new stack with the same properties.
342 */
343 public ItemStack copy()
344 {
345 ItemStack var1 = new ItemStack(this.itemID, this.stackSize, this.itemDamage);
346
347 if (this.stackTagCompound != null)
348 {
349 var1.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
350 }
351
352 return var1;
353 }
354
355 public static boolean areItemStackTagsEqual(ItemStack par0ItemStack, ItemStack par1ItemStack)
356 {
357 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? (par0ItemStack.stackTagCompound == null && par1ItemStack.stackTagCompound != null ? false : par0ItemStack.stackTagCompound == null || par0ItemStack.stackTagCompound.equals(par1ItemStack.stackTagCompound)) : false);
358 }
359
360 /**
361 * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal
362 */
363 public static boolean areItemStacksEqual(ItemStack par0ItemStack, ItemStack par1ItemStack)
364 {
365 return par0ItemStack == null && par1ItemStack == null ? true : (par0ItemStack != null && par1ItemStack != null ? par0ItemStack.isItemStackEqual(par1ItemStack) : false);
366 }
367
368 /**
369 * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal
370 */
371 private boolean isItemStackEqual(ItemStack par1ItemStack)
372 {
373 return this.stackSize != par1ItemStack.stackSize ? false : (this.itemID != par1ItemStack.itemID ? false : (this.itemDamage != par1ItemStack.itemDamage ? false : (this.stackTagCompound == null && par1ItemStack.stackTagCompound != null ? false : this.stackTagCompound == null || this.stackTagCompound.equals(par1ItemStack.stackTagCompound))));
374 }
375
376 /**
377 * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are
378 * equal
379 */
380 public boolean isItemEqual(ItemStack par1ItemStack)
381 {
382 return this.itemID == par1ItemStack.itemID && this.itemDamage == par1ItemStack.itemDamage;
383 }
384
385 public String getItemName()
386 {
387 return Item.itemsList[this.itemID].getItemNameIS(this);
388 }
389
390 /**
391 * Creates a copy of a ItemStack, a null parameters will return a null.
392 */
393 public static ItemStack copyItemStack(ItemStack par0ItemStack)
394 {
395 return par0ItemStack == null ? null : par0ItemStack.copy();
396 }
397
398 public String toString()
399 {
400 return this.stackSize + "x" + Item.itemsList[this.itemID].getItemName() + "@" + this.itemDamage;
401 }
402
403 /**
404 * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update
405 * maps.
406 */
407 public void updateAnimation(World par1World, Entity par2Entity, int par3, boolean par4)
408 {
409 if (this.animationsToGo > 0)
410 {
411 --this.animationsToGo;
412 }
413
414 Item.itemsList[this.itemID].onUpdate(this, par1World, par2Entity, par3, par4);
415 }
416
417 public void onCrafting(World par1World, EntityPlayer par2EntityPlayer, int par3)
418 {
419 par2EntityPlayer.addStat(StatList.objectCraftStats[this.itemID], par3);
420 Item.itemsList[this.itemID].onCreated(this, par1World, par2EntityPlayer);
421 }
422
423 public int getMaxItemUseDuration()
424 {
425 return this.getItem().getMaxItemUseDuration(this);
426 }
427
428 public EnumAction getItemUseAction()
429 {
430 return this.getItem().getItemUseAction(this);
431 }
432
433 /**
434 * Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount
435 */
436 public void onPlayerStoppedUsing(World par1World, EntityPlayer par2EntityPlayer, int par3)
437 {
438 this.getItem().onPlayerStoppedUsing(this, par1World, par2EntityPlayer, par3);
439 }
440
441 /**
442 * Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments.
443 */
444 public boolean hasTagCompound()
445 {
446 return this.stackTagCompound != null;
447 }
448
449 /**
450 * Returns the NBTTagCompound of the ItemStack.
451 */
452 public NBTTagCompound getTagCompound()
453 {
454 return this.stackTagCompound;
455 }
456
457 public NBTTagList getEnchantmentTagList()
458 {
459 return this.stackTagCompound == null ? null : (NBTTagList)this.stackTagCompound.getTag("ench");
460 }
461
462 /**
463 * Assigns a NBTTagCompound to the ItemStack, minecraft validates that only non-stackable items can have it.
464 */
465 public void setTagCompound(NBTTagCompound par1NBTTagCompound)
466 {
467 this.stackTagCompound = par1NBTTagCompound;
468 }
469
470 /**
471 * returns the display name of the itemstack
472 */
473 public String getDisplayName()
474 {
475 String var1 = this.getItem().getItemDisplayName(this);
476
477 if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display"))
478 {
479 NBTTagCompound var2 = this.stackTagCompound.getCompoundTag("display");
480
481 if (var2.hasKey("Name"))
482 {
483 var1 = var2.getString("Name");
484 }
485 }
486
487 return var1;
488 }
489
490 /**
491 * Sets the item's name (used by anvil to rename the items).
492 */
493 public void setItemName(String par1Str)
494 {
495 if (this.stackTagCompound == null)
496 {
497 this.stackTagCompound = new NBTTagCompound();
498 }
499
500 if (!this.stackTagCompound.hasKey("display"))
501 {
502 this.stackTagCompound.setCompoundTag("display", new NBTTagCompound());
503 }
504
505 this.stackTagCompound.getCompoundTag("display").setString("Name", par1Str);
506 }
507
508 /**
509 * Returns true if the itemstack has a display name
510 */
511 public boolean hasDisplayName()
512 {
513 return this.stackTagCompound == null ? false : (!this.stackTagCompound.hasKey("display") ? false : this.stackTagCompound.getCompoundTag("display").hasKey("Name"));
514 }
515
516 @SideOnly(Side.CLIENT)
517
518 /**
519 * Return a list of strings containing information about the item
520 */
521 public List getTooltip(EntityPlayer par1EntityPlayer, boolean par2)
522 {
523 ArrayList var3 = new ArrayList();
524 Item var4 = Item.itemsList[this.itemID];
525 String var5 = this.getDisplayName();
526
527 if (par2)
528 {
529 String var6 = "";
530
531 if (var5.length() > 0)
532 {
533 var5 = var5 + " (";
534 var6 = ")";
535 }
536
537 if (this.getHasSubtypes())
538 {
539 var5 = var5 + String.format("#%04d/%d%s", new Object[] {Integer.valueOf(this.itemID), Integer.valueOf(this.itemDamage), var6});
540 }
541 else
542 {
543 var5 = var5 + String.format("#%04d%s", new Object[] {Integer.valueOf(this.itemID), var6});
544 }
545 }
546 else if (!this.hasDisplayName())
547 {
548 if (this.itemID == Item.map.shiftedIndex)
549 {
550 var5 = var5 + " #" + this.itemDamage;
551 }
552 }
553 else
554 {
555 var5 = "\u00a7o" + var5;
556 }
557
558 var3.add(var5);
559 var4.addInformation(this, par1EntityPlayer, var3, par2);
560
561 if (this.hasTagCompound())
562 {
563 NBTTagList var10 = this.getEnchantmentTagList();
564
565 if (var10 != null)
566 {
567 for (int var7 = 0; var7 < var10.tagCount(); ++var7)
568 {
569 short var8 = ((NBTTagCompound)var10.tagAt(var7)).getShort("id");
570 short var9 = ((NBTTagCompound)var10.tagAt(var7)).getShort("lvl");
571
572 if (Enchantment.enchantmentsList[var8] != null)
573 {
574 var3.add(Enchantment.enchantmentsList[var8].getTranslatedName(var9));
575 }
576 }
577 }
578
579 if (this.stackTagCompound.hasKey("display"))
580 {
581 NBTTagCompound var11 = this.stackTagCompound.getCompoundTag("display");
582
583 if (var11.hasKey("color"))
584 {
585 if (par2)
586 {
587 var3.add("Color: #" + Integer.toHexString(var11.getInteger("color")).toUpperCase());
588 }
589 else
590 {
591 var3.add("\u00a7o" + StatCollector.translateToLocal("item.dyed"));
592 }
593 }
594
595 if (var11.hasKey("Lore"))
596 {
597 NBTTagList var12 = var11.getTagList("Lore");
598
599 if (var12.tagCount() > 0)
600 {
601 for (int var13 = 0; var13 < var12.tagCount(); ++var13)
602 {
603 var3.add("\u00a75\u00a7o" + ((NBTTagString)var12.tagAt(var13)).data);
604 }
605 }
606 }
607 }
608 }
609
610 if (par2 && this.isItemDamaged())
611 {
612 var3.add("Durability: " + (this.getMaxDamage() - this.getItemDamageForDisplay()) + " / " + this.getMaxDamage());
613 }
614
615 return var3;
616 }
617
618 @SideOnly(Side.CLIENT)
619 public boolean hasEffect()
620 {
621 return this.getItem().hasEffect(this);
622 }
623
624 @SideOnly(Side.CLIENT)
625 public EnumRarity getRarity()
626 {
627 return this.getItem().getRarity(this);
628 }
629
630 /**
631 * True if it is a tool and has no enchantments to begin with
632 */
633 public boolean isItemEnchantable()
634 {
635 return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
636 }
637
638 /**
639 * Adds an enchantment with a desired level on the ItemStack.
640 */
641 public void addEnchantment(Enchantment par1Enchantment, int par2)
642 {
643 if (this.stackTagCompound == null)
644 {
645 this.setTagCompound(new NBTTagCompound());
646 }
647
648 if (!this.stackTagCompound.hasKey("ench"))
649 {
650 this.stackTagCompound.setTag("ench", new NBTTagList("ench"));
651 }
652
653 NBTTagList var3 = (NBTTagList)this.stackTagCompound.getTag("ench");
654 NBTTagCompound var4 = new NBTTagCompound();
655 var4.setShort("id", (short)par1Enchantment.effectId);
656 var4.setShort("lvl", (short)((byte)par2));
657 var3.appendTag(var4);
658 }
659
660 /**
661 * True if the item has enchantment data
662 */
663 public boolean isItemEnchanted()
664 {
665 return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench");
666 }
667
668 public void func_77983_a(String par1Str, NBTBase par2NBTBase)
669 {
670 if (this.stackTagCompound == null)
671 {
672 this.setTagCompound(new NBTTagCompound());
673 }
674
675 this.stackTagCompound.setTag(par1Str, par2NBTBase);
676 }
677
678 public boolean func_82835_x()
679 {
680 return this.getItem().func_82788_x();
681 }
682
683 /**
684 * Return whether this stack is on an item frame.
685 */
686 public boolean isOnItemFrame()
687 {
688 return this.itemFrame != null;
689 }
690
691 /**
692 * Set the item frame this stack is on.
693 */
694 public void setItemFrame(EntityItemFrame par1EntityItemFrame)
695 {
696 this.itemFrame = par1EntityItemFrame;
697 }
698
699 /**
700 * Return the item frame this stack is on. Returns null if not on an item frame.
701 */
702 public EntityItemFrame getItemFrame()
703 {
704 return this.itemFrame;
705 }
706
707 /**
708 * Get this stack's repair cost, or 0 if no repair cost is defined.
709 */
710 public int getRepairCost()
711 {
712 return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost") ? this.stackTagCompound.getInteger("RepairCost") : 0;
713 }
714
715 /**
716 * Set this stack's repair cost.
717 */
718 public void setRepairCost(int par1)
719 {
720 if (!this.hasTagCompound())
721 {
722 this.stackTagCompound = new NBTTagCompound();
723 }
724
725 this.stackTagCompound.setInteger("RepairCost", par1);
726 }
727 }