the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "com.mojang.nbt.h"
3#include "net.minecraft.locale.h"
4#include "net.minecraft.stats.h"
5#include "net.minecraft.world.entity.h"
6#include "net.minecraft.world.entity.ai.attributes.h"
7#include "net.minecraft.world.entity.monster.h"
8#include "net.minecraft.world.entity.player.h"
9#include "net.minecraft.world.level.h"
10#include "net.minecraft.world.level.tile.h"
11#include "net.minecraft.world.item.h"
12#include "net.minecraft.world.item.enchantment.h"
13#include "Item.h"
14#include "ItemInstance.h"
15#include "HtmlString.h"
16
17const wstring ItemInstance::ATTRIBUTE_MODIFIER_FORMAT = L"#.###";
18
19const wchar_t *ItemInstance::TAG_ENCH_ID = L"id";
20const wchar_t *ItemInstance::TAG_ENCH_LEVEL = L"lvl";
21
22void ItemInstance::_init(int id, int count, int auxValue)
23{
24 this->popTime = 0;
25 this->id = id;
26 this->count = count;
27 this->auxValue = auxValue;
28 this->tag = NULL;
29 this->frame = nullptr;
30 // 4J-PB - for trading menu
31 this->m_bForceNumberDisplay=false;
32}
33
34ItemInstance::ItemInstance(Tile *tile)
35{
36 _init(tile->id, 1, 0);
37}
38
39ItemInstance::ItemInstance(Tile *tile, int count)
40{
41 _init(tile->id, count, 0);
42}
43// 4J-PB - added
44ItemInstance::ItemInstance(MapItem *item, int count)
45{
46 _init(item->id, count, 0);
47}
48
49ItemInstance::ItemInstance(Tile *tile, int count, int auxValue)
50{
51 _init(tile->id, count, auxValue);
52}
53
54ItemInstance::ItemInstance(Item *item)
55{
56 _init(item->id, 1, 0);
57}
58
59
60
61ItemInstance::ItemInstance(Item *item, int count)
62{
63 _init(item->id, count, 0);
64}
65
66ItemInstance::ItemInstance(Item *item, int count, int auxValue)
67{
68 _init(item->id, count, auxValue);
69}
70
71ItemInstance::ItemInstance(int id, int count, int damage)
72{
73 _init(id,count,damage);
74 if (auxValue < 0)
75 {
76 auxValue = 0;
77 }
78}
79
80shared_ptr<ItemInstance> ItemInstance::fromTag(CompoundTag *itemTag)
81{
82 shared_ptr<ItemInstance> itemInstance = shared_ptr<ItemInstance>(new ItemInstance());
83 itemInstance->load(itemTag);
84 return itemInstance->getItem() != NULL ? itemInstance : nullptr;
85}
86
87ItemInstance::~ItemInstance()
88{
89 if(tag != NULL) delete tag;
90}
91
92shared_ptr<ItemInstance> ItemInstance::remove(int count)
93{
94 shared_ptr<ItemInstance> ii = shared_ptr<ItemInstance>( new ItemInstance(id, count, auxValue) );
95 if (tag != NULL) ii->tag = (CompoundTag *) tag->copy();
96 this->count -= count;
97
98 // 4J Stu Fix for duplication glitch, make sure that item count is in range
99 if(this->count <= 0)
100 {
101 this->count = 0;
102 }
103 return ii;
104}
105
106Item *ItemInstance::getItem() const
107{
108 return Item::items[id];
109}
110
111Icon *ItemInstance::getIcon()
112{
113 return getItem()->getIcon(shared_from_this());
114}
115
116int ItemInstance::getIconType()
117{
118 return getItem()->getIconType();
119}
120
121bool ItemInstance::useOn(shared_ptr<Player> player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly)
122{
123 return getItem()->useOn(shared_from_this(), player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnOnly);
124}
125
126float ItemInstance::getDestroySpeed(Tile *tile)
127{
128 return getItem()->getDestroySpeed(shared_from_this(), tile);
129}
130
131bool ItemInstance::TestUse(shared_ptr<ItemInstance> itemInstance, Level *level, shared_ptr<Player> player)
132{
133 return getItem()->TestUse( itemInstance, level, player);
134}
135
136shared_ptr<ItemInstance> ItemInstance::use(Level *level, shared_ptr<Player> player)
137{
138 return getItem()->use(shared_from_this(), level, player);
139}
140
141shared_ptr<ItemInstance> ItemInstance::useTimeDepleted(Level *level, shared_ptr<Player> player)
142{
143 return getItem()->useTimeDepleted(shared_from_this(), level, player);
144}
145
146CompoundTag *ItemInstance::save(CompoundTag *compoundTag)
147{
148 compoundTag->putShort(L"id", (short) id);
149 compoundTag->putByte(L"Count", (byte) count);
150 compoundTag->putShort(L"Damage", (short) auxValue);
151 if (tag != NULL) compoundTag->put(L"tag", tag->copy());
152 return compoundTag;
153}
154
155void ItemInstance::load(CompoundTag *compoundTag)
156{
157 popTime = 0;
158 id = compoundTag->getShort(L"id");
159 count = compoundTag->getByte(L"Count");
160 auxValue = compoundTag->getShort(L"Damage");
161 if (auxValue < 0)
162 {
163 auxValue = 0;
164 }
165 if (compoundTag->contains(L"tag"))
166 {
167 delete tag;
168 tag = (CompoundTag *)compoundTag->getCompound(L"tag")->copy();
169 }
170}
171
172int ItemInstance::getMaxStackSize() const
173{
174 return getItem()->getMaxStackSize();
175}
176
177bool ItemInstance::isStackable()
178{
179 return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged());
180}
181
182bool ItemInstance::isDamageableItem()
183{
184 return Item::items[id]->getMaxDamage() > 0;
185}
186
187/**
188* Returns true if this item type only can be stacked with items that have
189* the same auxValue data.
190*
191* @return
192*/
193
194bool ItemInstance::isStackedByData()
195{
196 return Item::items[id]->isStackedByData();
197}
198
199bool ItemInstance::isDamaged()
200{
201 return isDamageableItem() && auxValue > 0;
202}
203
204int ItemInstance::getDamageValue()
205{
206 return auxValue;
207}
208
209int ItemInstance::getAuxValue() const
210{
211 return auxValue;
212}
213
214void ItemInstance::setAuxValue(int value)
215{
216 auxValue = value;
217 if (auxValue < 0)
218 {
219 auxValue = 0;
220 }
221}
222
223int ItemInstance::getMaxDamage()
224{
225 return Item::items[id]->getMaxDamage();
226}
227
228bool ItemInstance::hurt(int dmg, Random *random)
229{
230 if (!isDamageableItem())
231 {
232 return false;
233 }
234
235 if (dmg > 0)
236 {
237 int level = EnchantmentHelper::getEnchantmentLevel(Enchantment::digDurability->id, shared_from_this());
238
239 int drop = 0;
240 for (int y = 0; level > 0 && y < dmg; y++)
241 {
242 if (DigDurabilityEnchantment::shouldIgnoreDurabilityDrop(shared_from_this(), level, random))
243 {
244 drop++;
245 }
246 }
247 dmg -= drop;
248
249 if (dmg <= 0) return false;
250 }
251
252 auxValue += dmg;
253
254 return auxValue > getMaxDamage();
255}
256
257void ItemInstance::hurtAndBreak(int dmg, shared_ptr<LivingEntity> owner)
258{
259 shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner);
260 if (player != NULL && player->abilities.instabuild) return;
261 if (!isDamageableItem()) return;
262
263 if (hurt(dmg, owner->getRandom()))
264 {
265 owner->breakItem(shared_from_this());
266
267 count--;
268 if (player != NULL)
269 {
270 //player->awardStat(Stats::itemBroke[id], 1);
271 if (count == 0 && dynamic_cast<BowItem *>( getItem() ) != NULL)
272 {
273 player->removeSelectedItem();
274 }
275 }
276 if (count < 0) count = 0;
277 auxValue = 0;
278 }
279}
280
281void ItemInstance::hurtEnemy(shared_ptr<LivingEntity> mob, shared_ptr<Player> attacker)
282{
283 //bool used =
284 Item::items[id]->hurtEnemy(shared_from_this(), mob, attacker);
285}
286
287void ItemInstance::mineBlock(Level *level, int tile, int x, int y, int z, shared_ptr<Player> owner)
288{
289 //bool used =
290 Item::items[id]->mineBlock( shared_from_this(), level, tile, x, y, z, owner);
291}
292
293bool ItemInstance::canDestroySpecial(Tile *tile)
294{
295 return Item::items[id]->canDestroySpecial(tile);
296}
297
298bool ItemInstance::interactEnemy(shared_ptr<Player> player, shared_ptr<LivingEntity> mob)
299{
300 return Item::items[id]->interactEnemy(shared_from_this(), player, mob);
301}
302
303shared_ptr<ItemInstance> ItemInstance::copy() const
304{
305 shared_ptr<ItemInstance> copy = shared_ptr<ItemInstance>( new ItemInstance(id, count, auxValue) );
306 if (tag != NULL)
307 {
308 copy->tag = (CompoundTag *) tag->copy();
309 }
310 return copy;
311}
312
313// 4J Stu - Added this as we need it in the recipe code
314ItemInstance *ItemInstance::copy_not_shared() const
315{
316 ItemInstance *copy = new ItemInstance(id, count, auxValue);
317 if (tag != NULL)
318 {
319 copy->tag = (CompoundTag *) tag->copy();
320 if (!copy->tag->equals(tag))
321 {
322 return copy;
323 }
324 }
325 return copy;
326}
327
328// 4J Brought forward from 1.2
329bool ItemInstance::tagMatches(shared_ptr<ItemInstance> a, shared_ptr<ItemInstance> b)
330{
331 if (a == NULL && b == NULL) return true;
332 if (a == NULL || b == NULL) return false;
333
334 if (a->tag == NULL && b->tag != NULL)
335 {
336 return false;
337 }
338 if (a->tag != NULL && !a->tag->equals(b->tag))
339 {
340 return false;
341 }
342 return true;
343}
344
345bool ItemInstance::matches(shared_ptr<ItemInstance> a, shared_ptr<ItemInstance> b)
346{
347 if (a == NULL && b == NULL) return true;
348 if (a == NULL || b == NULL) return false;
349 return a->matches(b);
350}
351
352bool ItemInstance::matches(shared_ptr<ItemInstance> b)
353{
354 if (count != b->count) return false;
355 if (id != b->id) return false;
356 if (auxValue != b->auxValue) return false;
357 if (tag == NULL && b->tag != NULL)
358 {
359 return false;
360 }
361 if (tag != NULL && !tag->equals(b->tag))
362 {
363 return false;
364 }
365 return true;
366}
367
368/**
369* Checks if this item is the same item as the other one, disregarding the
370* 'count' value.
371*
372* @param b
373* @return
374*/
375bool ItemInstance::sameItem(shared_ptr<ItemInstance> b)
376{
377 return id == b->id && auxValue == b->auxValue;
378}
379
380bool ItemInstance::sameItemWithTags(shared_ptr<ItemInstance> b)
381{
382 if (id != b->id) return false;
383 if (auxValue != b->auxValue) return false;
384 if (tag == NULL && b->tag != NULL)
385 {
386 return false;
387 }
388 if (tag != NULL && !tag->equals(b->tag))
389 {
390 return false;
391 }
392 return true;
393}
394
395// 4J Stu - Added this for the one time when we compare with a non-shared pointer
396bool ItemInstance::sameItem_not_shared(const ItemInstance *b)
397{
398 return id == b->id && auxValue == b->auxValue;
399}
400
401unsigned int ItemInstance::getUseDescriptionId()
402{
403 return Item::items[id]->getUseDescriptionId(shared_from_this());
404}
405
406unsigned int ItemInstance::getDescriptionId(int iData /*= -1*/)
407{
408 return Item::items[id]->getDescriptionId(shared_from_this());
409}
410
411ItemInstance *ItemInstance::setDescriptionId(unsigned int id)
412{
413 // 4J Stu - I don't think this function is ever used. It if is, it should probably return shared_from_this()
414 assert(false);
415 return this;
416}
417
418shared_ptr<ItemInstance> ItemInstance::clone(shared_ptr<ItemInstance> item)
419{
420 return item == NULL ? nullptr : item->copy();
421}
422
423wstring ItemInstance::toString()
424{
425 //return count + "x" + Item::items[id]->getDescriptionId() + "@" + auxValue;
426
427 std::wostringstream oss;
428 // 4J-PB - TODO - temp fix until ore recipe issue is fixed
429 if(Item::items[id]==NULL)
430 {
431 oss << std::dec << count << L"x" << L" Item::items[id] is NULL " << L"@" << auxValue;
432 }
433 else
434 {
435 oss << std::dec << count << L"x" << Item::items[id]->getDescription(shared_from_this()) << L"@" << auxValue;
436 }
437 return oss.str();
438}
439
440void ItemInstance::inventoryTick(Level *level, shared_ptr<Entity> owner, int slot, bool selected)
441{
442 if (popTime > 0) popTime--;
443 Item::items[id]->inventoryTick(shared_from_this(), level, owner, slot, selected);
444}
445
446void ItemInstance::onCraftedBy(Level *level, shared_ptr<Player> player, int craftCount)
447{
448 // 4J Stu Added for tutorial callback
449 player->onCrafted(shared_from_this());
450
451 player->awardStat(
452 GenericStats::itemsCrafted(id),
453 GenericStats::param_itemsCrafted(id, auxValue, craftCount)
454 );
455
456 Item::items[id]->onCraftedBy(shared_from_this(), level, player);
457}
458
459bool ItemInstance::equals(shared_ptr<ItemInstance> ii)
460{
461 return id == ii->id && count == ii->count && auxValue == ii->auxValue;
462}
463
464int ItemInstance::getUseDuration()
465{
466 return getItem()->getUseDuration(shared_from_this());
467}
468
469UseAnim ItemInstance::getUseAnimation()
470{
471 return getItem()->getUseAnimation(shared_from_this());
472}
473
474void ItemInstance::releaseUsing(Level *level, shared_ptr<Player> player, int durationLeft)
475{
476 getItem()->releaseUsing(shared_from_this(), level, player, durationLeft);
477}
478
479// 4J Stu - Brought forward these functions for enchanting/game rules
480bool ItemInstance::hasTag()
481{
482 return tag != NULL;
483}
484
485CompoundTag *ItemInstance::getTag()
486{
487 return tag;
488}
489
490ListTag<CompoundTag> *ItemInstance::getEnchantmentTags()
491{
492 if (tag == NULL)
493 {
494 return NULL;
495 }
496 return (ListTag<CompoundTag> *) tag->get(L"ench");
497}
498
499void ItemInstance::setTag(CompoundTag *tag)
500{
501 delete this->tag;
502 this->tag = tag;
503}
504
505wstring ItemInstance::getHoverName()
506{
507 wstring title = getItem()->getHoverName(shared_from_this());
508
509 if (tag != NULL && tag->contains(L"display"))
510 {
511 CompoundTag *display = tag->getCompound(L"display");
512
513 if (display->contains(L"Name"))
514 {
515 title = display->getString(L"Name");
516 }
517 }
518
519 return title;
520}
521
522void ItemInstance::setHoverName(const wstring &name)
523{
524 if (tag == NULL) tag = new CompoundTag();
525 if (!tag->contains(L"display")) tag->putCompound(L"display", new CompoundTag());
526 tag->getCompound(L"display")->putString(L"Name", name);
527}
528
529void ItemInstance::resetHoverName()
530{
531 if (tag == NULL) return;
532 if (!tag->contains(L"display")) return;
533 CompoundTag *display = tag->getCompound(L"display");
534 display->remove(L"Name");
535
536 if (display->isEmpty())
537 {
538 tag->remove(L"display");
539
540 if (tag->isEmpty())
541 {
542 setTag(NULL);
543 }
544 }
545}
546
547bool ItemInstance::hasCustomHoverName()
548{
549 if (tag == NULL) return false;
550 if (!tag->contains(L"display")) return false;
551 return tag->getCompound(L"display")->contains(L"Name");
552}
553
554vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool advanced)
555{
556 vector<HtmlString> *lines = new vector<HtmlString>();
557 Item *item = Item::items[id];
558 HtmlString title = HtmlString(getHoverName());
559
560 if (hasCustomHoverName())
561 {
562 title.italics = true;
563 }
564
565 // 4J: This is for showing aux values, not useful in console version
566 /*
567 if (advanced)
568 {
569 wstring suffix = L"";
570
571 if (title.length() > 0)
572 {
573 title += L" (";
574 suffix = L")";
575 }
576
577 if (isStackedByData())
578 {
579 title += String.format("#%04d/%d%s", id, auxValue, suffix);
580 }
581 else
582 {
583 title += String.format("#%04d%s", id, suffix);
584 }
585 }
586 else if (!hasCustomHoverName() && id == Item::map_Id)
587 */
588
589 /*if (!hasCustomHoverName() && id == Item::map_Id)
590 {
591 title.text += L" #" + _toString(auxValue);
592 }*/
593
594 lines->push_back(title);
595
596 item->appendHoverText(shared_from_this(), player, lines, advanced);
597
598 if (hasTag())
599 {
600 ListTag<CompoundTag> *list = getEnchantmentTags();
601 if (list != NULL)
602 {
603 for (int i = 0; i < list->size(); i++)
604 {
605 int type = list->get(i)->getShort((wchar_t *)TAG_ENCH_ID);
606 int level = list->get(i)->getShort((wchar_t *)TAG_ENCH_LEVEL);
607
608 if (Enchantment::enchantments[type] != NULL)
609 {
610 wstring unformatted = L"";
611 lines->push_back(Enchantment::enchantments[type]->getFullname(level));
612 }
613 }
614 }
615
616 if (tag->contains(L"display"))
617 {
618 //CompoundTag *display = tag->getCompound(L"display");
619
620 //if (display->contains(L"color"))
621 //{
622 // if (advanced)
623 // {
624 // wchar_t text [256];
625 // swprintf(text, 256, L"Color: LOCALISE #%08X", display->getInt(L"color"));
626 // lines->push_back(HtmlString(text));
627 // }
628 // else
629 // {
630 // lines->push_back(HtmlString(L"Dyed LOCALISE", eMinecraftColour_NOT_SET, true));
631 // }
632 //}
633
634 // 4J: Lore isn't in use in game
635 /*if (display->contains(L"Lore"))
636 {
637 ListTag<StringTag> *lore = (ListTag<StringTag> *) display->getList(L"Lore");
638 if (lore->size() > 0)
639 {
640 for (int i = 0; i < lore->size(); i++)
641 {
642 //lines->push_back(ChatFormatting::DARK_PURPLE + "" + ChatFormatting::ITALIC + lore->get(i)->data);
643 lines->push_back(lore->get(i)->data);
644 }
645 }
646 }*/
647 }
648 }
649
650 attrAttrModMap *modifiers = getAttributeModifiers();
651
652 if (!modifiers->empty())
653 {
654 // New line
655 lines->push_back(HtmlString(L""));
656
657 // Modifier descriptions
658 for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it)
659 {
660 // 4J: Moved modifier string building to AttributeModifier
661 lines->push_back(it->second->getHoverText(it->first));
662 }
663 }
664
665 // Delete modifiers map
666 for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it)
667 {
668 AttributeModifier *modifier = it->second;
669 delete modifier;
670 }
671 delete modifiers;
672
673 if (advanced)
674 {
675 if (isDamaged())
676 {
677 wstring damageStr = L"Durability: LOCALISE " + _toString<int>((getMaxDamage()) - getDamageValue()) + L" / " + _toString<int>(getMaxDamage());
678 lines->push_back(HtmlString(damageStr));
679 }
680 }
681
682 return lines;
683}
684
685// 4J Added
686vector<HtmlString> *ItemInstance::getHoverTextOnly(shared_ptr<Player> player, bool advanced)
687{
688 vector<HtmlString> *lines = new vector<HtmlString>();
689 Item *item = Item::items[id];
690
691 item->appendHoverText(shared_from_this(), player, lines, advanced);
692
693 if (hasTag())
694 {
695 ListTag<CompoundTag> *list = getEnchantmentTags();
696 if (list != NULL)
697 {
698 for (int i = 0; i < list->size(); i++)
699 {
700 int type = list->get(i)->getShort((wchar_t *)TAG_ENCH_ID);
701 int level = list->get(i)->getShort((wchar_t *)TAG_ENCH_LEVEL);
702
703 if (Enchantment::enchantments[type] != NULL)
704 {
705 wstring unformatted = L"";
706 lines->push_back(Enchantment::enchantments[type]->getFullname(level));
707 }
708 }
709 }
710 }
711 return lines;
712}
713
714bool ItemInstance::isFoil()
715{
716 return getItem()->isFoil(shared_from_this());
717}
718
719const Rarity *ItemInstance::getRarity()
720{
721 return getItem()->getRarity(shared_from_this());
722}
723
724bool ItemInstance::isEnchantable()
725{
726 if (!getItem()->isEnchantable(shared_from_this())) return false;
727 if (isEnchanted()) return false;
728 return true;
729}
730
731void ItemInstance::enchant(const Enchantment *enchantment, int level)
732{
733 if (tag == NULL) this->setTag(new CompoundTag());
734 if (!tag->contains(L"ench")) tag->put(L"ench", new ListTag<CompoundTag>(L"ench"));
735
736 ListTag<CompoundTag> *list = (ListTag<CompoundTag> *) tag->get(L"ench");
737 CompoundTag *ench = new CompoundTag();
738 ench->putShort((wchar_t *)TAG_ENCH_ID, (short) enchantment->id);
739 ench->putShort((wchar_t *)TAG_ENCH_LEVEL, (byte) level);
740 list->add(ench);
741}
742
743bool ItemInstance::isEnchanted()
744{
745 if (tag != NULL && tag->contains(L"ench")) return true;
746 return false;
747}
748
749void ItemInstance::addTagElement(wstring name, Tag *tag)
750{
751 if (this->tag == NULL)
752 {
753 setTag(new CompoundTag());
754 }
755 this->tag->put((wchar_t *)name.c_str(), tag);
756}
757
758bool ItemInstance::mayBePlacedInAdventureMode()
759{
760 return getItem()->mayBePlacedInAdventureMode();
761}
762
763bool ItemInstance::isFramed()
764{
765 return frame != NULL;
766}
767
768void ItemInstance::setFramed(shared_ptr<ItemFrame> frame)
769{
770 this->frame = frame;
771}
772
773shared_ptr<ItemFrame> ItemInstance::getFrame()
774{
775 return frame;
776}
777
778int ItemInstance::getBaseRepairCost()
779{
780 if (hasTag() && tag->contains(L"RepairCost"))
781 {
782 return tag->getInt(L"RepairCost");
783 }
784 else
785 {
786 return 0;
787 }
788}
789
790void ItemInstance::setRepairCost(int cost)
791{
792 if (!hasTag()) tag = new CompoundTag();
793 tag->putInt(L"RepairCost", cost);
794}
795
796attrAttrModMap *ItemInstance::getAttributeModifiers()
797{
798 attrAttrModMap *result = NULL;
799
800 if (hasTag() && tag->contains(L"AttributeModifiers"))
801 {
802 result = new attrAttrModMap();
803 ListTag<CompoundTag> *entries = (ListTag<CompoundTag> *) tag->getList(L"AttributeModifiers");
804
805 for (int i = 0; i < entries->size(); i++)
806 {
807 CompoundTag *entry = entries->get(i);
808 AttributeModifier *attribute = SharedMonsterAttributes::loadAttributeModifier(entry);
809
810 // 4J Not sure why but this is a check that the attribute ID is not empty
811 /*if (attribute->getId()->getLeastSignificantBits() != 0 && attribute->getId()->getMostSignificantBits() != 0)
812 {*/
813 result->insert(std::pair<eATTRIBUTE_ID, AttributeModifier *>(static_cast<eATTRIBUTE_ID>(entry->getInt(L"ID")), attribute));
814 /*}*/
815 }
816 }
817 else
818 {
819 result = getItem()->getDefaultAttributeModifiers();
820 }
821
822 return result;
823}
824
825void ItemInstance::set4JData(int data)
826{
827 if(tag == NULL && data == 0) return;
828 if (tag == NULL) this->setTag(new CompoundTag());
829
830 if (tag->contains(L"4jdata"))
831 {
832 IntTag *dataTag = (IntTag *)tag->get(L"4jdata");
833 dataTag->data = data;
834 }
835 else if(data != 0)
836 {
837 tag->put(L"4jdata", new IntTag(L"4jdata",data));
838 }
839}
840
841int ItemInstance::get4JData()
842{
843 if(tag == NULL || !tag->contains(L"4jdata")) return 0;
844 else
845 {
846 IntTag *dataTag = (IntTag *)tag->get(L"4jdata");
847 return dataTag->data;
848 }
849}
850// 4J Added - to show strength on potions
851bool ItemInstance::hasPotionStrengthBar()
852{
853 // exclude a bottle of water from this
854 if((id==Item::potion_Id) && (auxValue !=0))// && (!MACRO_POTION_IS_AKWARD(auxValue))) 4J-PB leaving the bar on an awkward potion so we can differentiate it from a water bottle
855 {
856 return true;
857 }
858
859 return false;
860}
861
862int ItemInstance::GetPotionStrength()
863{
864 if(MACRO_POTION_IS_INSTANTDAMAGE(auxValue) || MACRO_POTION_IS_INSTANTHEALTH(auxValue) )
865 {
866 // The two instant potions don't have extended versions
867 return (auxValue&MASK_LEVEL2)>>5;
868 }
869 else
870 {
871 return (auxValue&MASK_LEVEL2EXTENDED)>>5;
872 }
873}