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