aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/Inventory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/Inventory.cpp')
-rw-r--r--Minecraft.World/Inventory.cpp746
1 files changed, 746 insertions, 0 deletions
diff --git a/Minecraft.World/Inventory.cpp b/Minecraft.World/Inventory.cpp
new file mode 100644
index 00000000..8ef3f085
--- /dev/null
+++ b/Minecraft.World/Inventory.cpp
@@ -0,0 +1,746 @@
+#include "stdafx.h"
+#include "com.mojang.nbt.h"
+#include "net.minecraft.world.entity.player.h"
+#include "net.minecraft.world.item.h"
+#include "net.minecraft.world.level.tile.h"
+#include "net.minecraft.stats.h"
+#include "Material.h"
+#include "Inventory.h"
+
+const int Inventory::POP_TIME_DURATION = 5;
+const int Inventory::MAX_INVENTORY_STACK_SIZE = 64;
+
+const int Inventory::INVENTORY_SIZE = 4 * 9;
+const int Inventory::SELECTION_SIZE = 9;
+
+// 4J Stu - The Pllayer is managed by shared_ptrs elsewhere, but it owns us so we don't want to also
+// keep a shared_ptr of it. If we pass it on we should use shared_from_this() though
+Inventory::Inventory(Player *player)
+{
+ items = ItemInstanceArray( INVENTORY_SIZE );
+ armor = ItemInstanceArray( 4 );
+
+ selected = 0;
+
+ carried = nullptr;
+
+ changed = false;
+
+ this->player = player;
+}
+
+Inventory::~Inventory()
+{
+ delete [] items.data;
+ delete [] armor.data;
+}
+
+shared_ptr<ItemInstance> Inventory::getSelected()
+{
+ // sanity checking to prevent exploits
+ if (selected < SELECTION_SIZE && selected >= 0)
+ {
+ return items[selected];
+ }
+ return nullptr;
+}
+
+// 4J-PB - Added for the in-game tooltips
+bool Inventory::IsHeldItem()
+{
+ // sanity checking to prevent exploits
+ if (selected < SELECTION_SIZE && selected >= 0)
+ {
+ if(items[selected])
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+int Inventory::getSelectionSize()
+{
+ return SELECTION_SIZE;
+}
+
+
+int Inventory::getSlot(int tileId)
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->id == tileId) return i;
+ }
+ return -1;
+}
+
+int Inventory::getSlot(int tileId, int data)
+{
+ for (int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->id == tileId && items[i]->getAuxValue() == data) return i;
+ }
+ return -1;
+}
+
+int Inventory::getSlotWithRemainingSpace(shared_ptr<ItemInstance> item)
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->id == item->id && items[i]->isStackable()
+ && items[i]->count < items[i]->getMaxStackSize() && items[i]->count < getMaxStackSize()
+ && (!items[i]->isStackedByData() || items[i]->getAuxValue() == item->getAuxValue())
+ && ItemInstance::tagMatches(items[i], item))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int Inventory::getFreeSlot()
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] == NULL) return i;
+ }
+ return -1;
+}
+
+
+void Inventory::grabTexture(int id, int data, bool checkData, bool mayReplace)
+{
+ int slot = -1;
+ heldItem = getSelected();
+ if (checkData)
+ {
+ slot = getSlot(id, data);
+ }
+ else
+ {
+ slot = getSlot(id);
+ }
+ if (slot >= 0 && slot < 9)
+ {
+ selected = slot;
+ return;
+ }
+
+ if (mayReplace)
+ {
+ if (id > 0)
+ {
+ int firstEmpty = getFreeSlot();
+ if (firstEmpty >= 0 && firstEmpty < 9)
+ {
+ selected = firstEmpty;
+ }
+
+ replaceSlot(Item::items[id], data);
+ }
+ }
+}
+
+void Inventory::swapPaint(int wheel)
+{
+ if (wheel > 0) wheel = 1;
+ if (wheel < 0) wheel = -1;
+
+ selected -= wheel;
+
+ while (selected < 0)
+ selected += 9;
+ while (selected >= 9)
+ selected -= 9;
+}
+
+void Inventory::clearInventory()
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ items[i] = nullptr;
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ armor[i] = nullptr;
+ }
+}
+
+void Inventory::replaceSlot(Item *item, int data)
+{
+ if (item != NULL)
+ {
+ int oldSlot = getSlot(item->id, data);
+ if (oldSlot >= 0)
+ {
+ items[oldSlot] = items[selected];
+ }
+
+ // It's too easy to accidentally pick block and lose enchanted
+ // items.
+ if (heldItem != NULL && heldItem->isEnchantable() && getSlot(heldItem->id, heldItem->getDamageValue()) == selected)
+ {
+ return;
+ }
+ items[selected] = shared_ptr<ItemInstance>(new ItemInstance(Item::items[item->id], 1, data));
+ }
+}
+
+
+int Inventory::addResource(shared_ptr<ItemInstance> itemInstance)
+{
+
+ int type = itemInstance->id;
+ int count = itemInstance->count;
+
+ // 4J Stu - Brought forward from 1.2
+ if (itemInstance->getMaxStackSize() == 1)
+ {
+ int slot = getFreeSlot();
+ if (slot < 0) return count;
+ if (items[slot] == NULL)
+ {
+ items[slot] = ItemInstance::clone(itemInstance);
+ player->handleCollectItem(itemInstance);
+ }
+ return 0;
+ }
+
+ int slot = getSlotWithRemainingSpace(itemInstance);
+ if (slot < 0) slot = getFreeSlot();
+ if (slot < 0) return count;
+ if (items[slot] == NULL)
+ {
+ items[slot] = shared_ptr<ItemInstance>( new ItemInstance(type, 0, itemInstance->getAuxValue()) );
+ // 4J Stu - Brought forward from 1.2
+ if (itemInstance->hasTag())
+ {
+ items[slot]->setTag((CompoundTag *) itemInstance->getTag()->copy());
+ player->handleCollectItem(itemInstance);
+ }
+ }
+
+ int toAdd = count;
+ if (toAdd > items[slot]->getMaxStackSize() - items[slot]->count)
+ {
+ toAdd = items[slot]->getMaxStackSize() - items[slot]->count;
+ }
+ if (toAdd > getMaxStackSize() - items[slot]->count)
+ {
+ toAdd = getMaxStackSize() - items[slot]->count;
+ }
+
+ if (toAdd == 0) return count;
+
+ count -= toAdd;
+ items[slot]->count += toAdd;
+ items[slot]->popTime = POP_TIME_DURATION;
+
+ return count;
+}
+
+
+void Inventory::tick()
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL)
+ {
+ items[i]->inventoryTick(player->level, player->shared_from_this(), i, selected == i);
+ }
+ }
+}
+
+bool Inventory::removeResource(int type)
+{
+ int slot = getSlot(type);
+ if (slot < 0) return false;
+ if (--items[slot]->count <= 0) items[slot] = nullptr;
+
+ return true;
+}
+
+bool Inventory::removeResource(int type,int iAuxVal)
+{
+ int slot = getSlot(type,iAuxVal);
+ if (slot < 0) return false;
+ if (--items[slot]->count <= 0) items[slot] = nullptr;
+
+ return true;
+}
+
+void Inventory::removeResources(shared_ptr<ItemInstance> item)
+{
+ if(item == NULL) return;
+
+ int countToRemove = item->count;
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->sameItemWithTags(item))
+ {
+ int slotCount = items[i]->count;
+ items[i]->count -= countToRemove;
+ if(slotCount < countToRemove)
+ {
+ countToRemove -= slotCount;
+ }
+ else
+ {
+ countToRemove = 0;
+ }
+ if(items[i]->count <= 0) items[i] = nullptr;
+ }
+ }
+}
+
+shared_ptr<ItemInstance> Inventory::getResourceItem(int type)
+{
+ int slot = getSlot(type);
+ if (slot < 0) return nullptr;
+ return getItem( slot );
+}
+
+shared_ptr<ItemInstance> Inventory::getResourceItem(int type,int iAuxVal)
+{
+ int slot = getSlot(type,iAuxVal);
+ if (slot < 0) return nullptr;
+ return getItem( slot );
+}
+
+bool Inventory::hasResource(int type)
+{
+ int slot = getSlot(type);
+ if (slot < 0) return false;
+
+ return true;
+}
+
+void Inventory::swapSlots(int from, int to)
+{
+ shared_ptr<ItemInstance> tmp = items[to];
+ items[to] = items[from];
+ items[from] = tmp;
+}
+
+bool Inventory::add(shared_ptr<ItemInstance> item)
+{
+ // 4J Stu - Fix for duplication glitch
+ if(item->count <= 0) return true;
+
+ if (!item->isDamaged())
+ {
+ int lastSize;
+ int count = item->count;
+ do
+ {
+ lastSize = item->count;
+ item->count = addResource(item);
+ } while (item->count > 0 && item->count < lastSize);
+ if (item->count == lastSize && player->abilities.instabuild)
+ {
+ // silently destroy the item when having a full inventory
+ item->count = 0;
+ return true;
+ }
+ if( item->count < lastSize )
+ {
+ player->awardStat(
+ GenericStats::itemsCollected(item->id, item->getAuxValue()),
+ GenericStats::param_itemsCollected(item->id, item->getAuxValue(), count)
+ );
+ return true;
+ }
+ else
+ return false;
+ }
+
+ int slot = getFreeSlot();
+ if (slot >= 0)
+ {
+ player->handleCollectItem(item);
+
+ player->awardStat(
+ GenericStats::itemsCollected(item->id, item->getAuxValue()),
+ GenericStats::param_itemsCollected(item->id, item->getAuxValue(), item->GetCount()));
+
+ items[slot] = ItemInstance::clone(item);
+ items[slot]->popTime = Inventory::POP_TIME_DURATION;
+ item->count = 0;
+ return true;
+ }
+ else if (player->abilities.instabuild)
+ {
+ // silently destroy the item when having a full inventory
+ item->count = 0;
+ return true;
+ }
+ return false;
+}
+
+shared_ptr<ItemInstance> Inventory::removeItem(unsigned int slot, int count)
+{
+
+ ItemInstanceArray pile = items;
+ if (slot >= items.length)
+ {
+ pile = armor;
+ slot -= items.length;
+ }
+
+ if (pile[slot] != NULL)
+ {
+ if (pile[slot]->count <= count)
+ {
+ shared_ptr<ItemInstance> item = pile[slot];
+ pile[slot] = nullptr;
+ return item;
+ }
+ else
+ {
+ shared_ptr<ItemInstance> i = pile[slot]->remove(count);
+ if (pile[slot]->count == 0) pile[slot] = nullptr;
+ return i;
+ }
+ }
+ return nullptr;
+}
+
+shared_ptr<ItemInstance> Inventory::removeItemNoUpdate(int slot)
+{
+ ItemInstanceArray pile = items;
+ if (slot >= items.length)
+ {
+ pile = armor;
+ slot -= items.length;
+ }
+
+ if (pile[slot] != NULL)
+ {
+ shared_ptr<ItemInstance> item = pile[slot];
+ pile[slot] = nullptr;
+ return item;
+ }
+ return nullptr;
+}
+
+void Inventory::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
+{
+#ifdef _DEBUG
+ if(item!=NULL)
+ {
+ wstring itemstring=item->toString();
+ app.DebugPrintf("Inventory::setItem - slot = %d,\t item = %d ",slot,item->id);
+ //OutputDebugStringW(itemstring.c_str());
+ app.DebugPrintf("\n");
+ }
+#else
+ if(item!=NULL)
+ {
+ app.DebugPrintf("Inventory::setItem - slot = %d,\t item = %d, aux = %d\n",slot,item->id,item->getAuxValue());
+ }
+#endif
+ // 4J Stu - Changed this a little from Java to be less funn
+ if( slot >= items.length )
+ {
+ armor[slot - items.length] = item;
+ }
+ else
+ {
+ items[slot] = item;
+ }
+ player->handleCollectItem(item);
+ /*
+ ItemInstanceArray& pile = items;
+ if (slot >= pile.length)
+ {
+ slot -= pile.length;
+ pile = armor;
+ }
+
+ pile[slot] = item;
+ */
+}
+
+float Inventory::getDestroySpeed(Tile *tile)
+{
+ float speed = 1.0f;
+ if (items[selected] != NULL) speed *= items[selected]->getDestroySpeed(tile);
+ return speed;
+}
+
+ListTag<CompoundTag> *Inventory::save(ListTag<CompoundTag> *listTag)
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL)
+ {
+ CompoundTag *tag = new CompoundTag();
+ tag->putByte(L"Slot", (byte) i);
+ items[i]->save(tag);
+ listTag->add(tag);
+ }
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (armor[i] != NULL)
+ {
+ CompoundTag *tag = new CompoundTag();
+ tag->putByte(L"Slot", (byte) (i + 100));
+ armor[i]->save(tag);
+ listTag->add(tag);
+ }
+ }
+ return listTag;
+}
+
+void Inventory::load(ListTag<CompoundTag> *inventoryList)
+{
+ if( items.data != NULL)
+ {
+ delete[] items.data;
+ items.data = NULL;
+ }
+ if( armor.data != NULL)
+ {
+ delete[] armor.data;
+ armor.data = NULL;
+
+ }
+ items = ItemInstanceArray( INVENTORY_SIZE );
+ armor = ItemInstanceArray( 4 );
+ for (int i = 0; i < inventoryList->size(); i++)
+ {
+ CompoundTag *tag = inventoryList->get(i);
+ unsigned int slot = tag->getByte(L"Slot") & 0xff;
+ shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>( ItemInstance::fromTag(tag) );
+ if (item != NULL)
+ {
+ if (slot >= 0 && slot < items.length) items[slot] = item;
+ if (slot >= 100 && slot < armor.length + 100) armor[slot - 100] = item;
+ }
+ }
+}
+
+unsigned int Inventory::getContainerSize()
+{
+ return items.length + 4;
+}
+
+shared_ptr<ItemInstance> Inventory::getItem(unsigned int slot)
+{
+ // 4J Stu - Changed this a little from the Java so it's less funny
+ if( slot >= items.length )
+ {
+ return armor[ slot - items.length ];
+ }
+ else
+ {
+ return items[ slot ];
+ }
+ /*
+ ItemInstanceArray pile = items;
+ if (slot >= pile.length)
+ {
+ slot -= pile.length;
+ pile = armor;
+ }
+
+ return pile[slot];
+ */
+}
+
+int Inventory::getName()
+{
+ return IDS_INVENTORY;
+}
+
+int Inventory::getMaxStackSize()
+{
+ return MAX_INVENTORY_STACK_SIZE;
+}
+
+int Inventory::getAttackDamage(shared_ptr<Entity> entity)
+{
+ shared_ptr<ItemInstance> item = getItem(selected);
+ if (item != NULL) return item->getAttackDamage(entity);
+ return 1;
+}
+
+bool Inventory::canDestroy(Tile *tile)
+{
+ if (tile->material->isAlwaysDestroyable()) return true;
+
+ shared_ptr<ItemInstance> item = getItem(selected);
+ if (item != NULL) return item->canDestroySpecial(tile);
+ return false;
+}
+
+shared_ptr<ItemInstance> Inventory::getArmor(int layer)
+{
+ return armor[layer];
+}
+
+int Inventory::getArmorValue()
+{
+ int val = 0;
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (armor[i] != NULL && dynamic_cast<ArmorItem *>( armor[i]->getItem() ) != NULL )
+ {
+ int baseProtection = dynamic_cast<ArmorItem *>(armor[i]->getItem())->defense;
+
+ val += baseProtection;
+ }
+ }
+ return val;
+}
+
+void Inventory::hurtArmor(int dmg)
+{
+ dmg = dmg / 4;
+ if (dmg < 1)
+ {
+ dmg = 1;
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (armor[i] != NULL && dynamic_cast<ArmorItem *>( armor[i]->getItem() ) != NULL )
+ {
+ armor[i]->hurt(dmg, dynamic_pointer_cast<Mob>( player->shared_from_this() ) );
+ if (armor[i]->count == 0)
+ {
+ armor[i] = nullptr;
+ }
+ }
+ }
+}
+
+void Inventory::dropAll()
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL)
+ {
+ player->drop(items[i], true);
+ items[i] = nullptr;
+ }
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (armor[i] != NULL)
+ {
+ player->drop(armor[i], true);
+ armor[i] = nullptr;
+ }
+ }
+}
+
+void Inventory::setChanged()
+{
+ changed = true;
+}
+
+bool Inventory::isSame(shared_ptr<Inventory> copy)
+{
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (!isSame( copy->items[i], items[i])) return false;
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (!isSame( copy->armor[i], armor[i])) return false;
+ }
+ return true;
+}
+
+
+bool Inventory::isSame(shared_ptr<ItemInstance> a, shared_ptr<ItemInstance> b)
+{
+ if (a == NULL && b == NULL) return true;
+ if (a == NULL || b == NULL) return false;
+
+ return a->id == b->id && a->count == b->count && a->getAuxValue() == b->getAuxValue();
+}
+
+
+shared_ptr<Inventory> Inventory::copy()
+{
+ shared_ptr<Inventory> copy = shared_ptr<Inventory>( new Inventory(NULL) );
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ copy->items[i] = items[i] != NULL ? items[i]->copy() : nullptr;
+ }
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ copy->armor[i] = armor[i] != NULL ? armor[i]->copy() : nullptr;
+ }
+ return copy;
+}
+
+void Inventory::setCarried(shared_ptr<ItemInstance> carried)
+{
+ this->carried = carried;
+ player->handleCollectItem(carried);
+}
+
+shared_ptr<ItemInstance> Inventory::getCarried()
+{
+ return carried;
+}
+
+bool Inventory::stillValid(shared_ptr<Player> player)
+{
+ if (this->player->removed) return false;
+ if (player->distanceToSqr(this->player->shared_from_this()) > 8 * 8) return false;
+ return true;
+}
+
+bool Inventory::contains(shared_ptr<ItemInstance> itemInstance)
+{
+ for (unsigned int i = 0; i < armor.length; i++)
+ {
+ if (armor[i] != NULL && armor[i]->equals(itemInstance)) return true;
+ }
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->equals(itemInstance)) return true;
+ }
+ return false;
+}
+
+void Inventory::startOpen()
+{
+ // TODO Auto-generated method stub
+}
+
+void Inventory::stopOpen()
+{
+ // TODO Auto-generated method stub
+}
+
+void Inventory::replaceWith(shared_ptr<Inventory> other)
+{
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i] = ItemInstance::clone(other->items[i]);
+ }
+ for (int i = 0; i < armor.length; i++)
+ {
+ armor[i] = ItemInstance::clone(other->armor[i]);
+ }
+}
+
+int Inventory::countMatches(shared_ptr<ItemInstance> itemInstance)
+{
+ if(itemInstance == NULL) return 0;
+ int count = 0;
+ //for (unsigned int i = 0; i < armor.length; i++)
+ //{
+ // if (armor[i] != NULL && armor[i]->sameItem(itemInstance)) count += items[i]->count;
+ //}
+ for (unsigned int i = 0; i < items.length; i++)
+ {
+ if (items[i] != NULL && items[i]->sameItemWithTags(itemInstance)) count += items[i]->count;
+ }
+ return count;
+}