#include "../../Platform/stdafx.h" #include "../../Headers/com.mojang.nbt.h" #include "BrewingStandTileEntity.h" #include "../../Util/SharedConstants.h" #include "../../Headers/net.minecraft.h" #include "../../Headers/net.minecraft.world.level.h" #include "../../Headers/net.minecraft.world.item.h" #include "../../Headers/net.minecraft.world.item.alchemy.h" int slotsForUp[] = {BrewingStandTileEntity::INGREDIENT_SLOT}; int slotsForOtherFaces[] = {0, 1, 2}; intArray BrewingStandTileEntity::SLOTS_FOR_UP = intArray(slotsForUp, 1); intArray BrewingStandTileEntity::SLOTS_FOR_OTHER_FACES = intArray(slotsForOtherFaces, 3); BrewingStandTileEntity::BrewingStandTileEntity() { brewTime = 0; items = ItemInstanceArray(4); name = L""; } BrewingStandTileEntity::~BrewingStandTileEntity() { delete[] items.data; } std::wstring BrewingStandTileEntity::getName() { return hasCustomName() ? name : app.GetString(IDS_TILE_BREWINGSTAND); } std::wstring BrewingStandTileEntity::getCustomName() { return hasCustomName() ? name : L""; } bool BrewingStandTileEntity::hasCustomName() { return !name.empty(); } void BrewingStandTileEntity::setCustomName(const std::wstring& name) { this->name = name; } unsigned int BrewingStandTileEntity::getContainerSize() { return items.length; } void BrewingStandTileEntity::tick() { if (brewTime > 0) { brewTime--; if (brewTime == 0) { // apply ingredients to all potions doBrew(); setChanged(); } else if (!isBrewable()) { brewTime = 0; setChanged(); } else if (ingredientId != items[INGREDIENT_SLOT]->id) { brewTime = 0; setChanged(); } } else if (isBrewable()) { brewTime = SharedConstants::TICKS_PER_SECOND * PotionBrewing::BREWING_TIME_SECONDS; ingredientId = items[INGREDIENT_SLOT]->id; } int newCount = getPotionBits(); if (newCount != lastPotionCount) { lastPotionCount = newCount; level->setData(x, y, z, newCount, Tile::UPDATE_CLIENTS); } TileEntity::tick(); } int BrewingStandTileEntity::getBrewTime() { return brewTime; } bool BrewingStandTileEntity::isBrewable() { if (items[INGREDIENT_SLOT] == nullptr || items[INGREDIENT_SLOT]->count <= 0) { return false; } std::shared_ptr ingredient = items[INGREDIENT_SLOT]; if (PotionBrewing::SIMPLIFIED_BREWING) { if (!Item::items[ingredient->id]->hasPotionBrewingFormula()) { return false; } bool oneResult = false; for (int dest = 0; dest < 3; dest++) { if (items[dest] != nullptr && items[dest]->id == Item::potion_Id) { int currentBrew = items[dest]->getAuxValue(); int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient)); if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) { oneResult = true; break; } std::vector* currentEffects = Item::potion->getMobEffects(currentBrew); std::vector* newEffects = Item::potion->getMobEffects(newBrew); // 4J - this code replaces an expression // "currentEffects.equals(newEffects)" in the java. // TODO - find out whether actually checking pointers to // MobEffectInstance classes for equality is of any use bool equals = false; if ((currentEffects != nullptr) && (newEffects != nullptr)) { if (currentEffects->size() == newEffects->size()) { if (std::equal(currentEffects->begin(), currentEffects->end(), newEffects->begin())) { equals = true; } } } if ((currentBrew > 0 && currentEffects == newEffects) || (currentEffects != nullptr && (equals || newEffects == nullptr))) { } else if (currentBrew != newBrew) { oneResult = true; break; } } } return oneResult; } else { if (!Item::items[ingredient->id]->hasPotionBrewingFormula() && ingredient->id != Item::bucket_water_Id && ingredient->id != Item::netherwart_seeds_Id) { return false; } bool isWater = ingredient->id == Item::bucket_water_Id; // at least one destination potion must have a result bool oneResult = false; for (int dest = 0; dest < 3; dest++) { if (items[dest] != nullptr && items[dest]->id == Item::potion_Id) { int currentBrew = items[dest]->getAuxValue(); int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient)); if (currentBrew != newBrew) { oneResult = true; break; } } else if (isWater && items[dest] != nullptr && items[dest]->id == Item::glassBottle_Id) { oneResult = true; break; } } return oneResult; } } void BrewingStandTileEntity::doBrew() { if (!isBrewable()) { return; } std::shared_ptr ingredient = items[INGREDIENT_SLOT]; if (PotionBrewing::SIMPLIFIED_BREWING) { for (int dest = 0; dest < 3; dest++) { if (items[dest] != nullptr && items[dest]->id == Item::potion_Id) { int currentBrew = items[dest]->getAuxValue(); int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient)); std::vector* currentEffects = Item::potion->getMobEffects(currentBrew); std::vector* newEffects = Item::potion->getMobEffects(newBrew); // 4J - this code replaces an expression // "currentEffects.equals(newEffects)" in the java. // TODO - find out whether actually checking pointers to // MobEffectInstance classes for equality is of any use bool equals = false; if ((currentEffects != nullptr) && (newEffects != nullptr)) { if (currentEffects->size() == newEffects->size()) { if (std::equal(currentEffects->begin(), currentEffects->end(), newEffects->begin())) { equals = true; } } } if ((currentBrew > 0 && currentEffects == newEffects) || (currentEffects != nullptr && (equals || newEffects == nullptr))) { if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) { items[dest]->setAuxValue(newBrew); } } else if (currentBrew != newBrew) { items[dest]->setAuxValue(newBrew); } } } } else { bool isWater = ingredient->id == Item::bucket_water_Id; for (int dest = 0; dest < 3; dest++) { if (items[dest] != nullptr && items[dest]->id == Item::potion_Id) { int currentBrew = items[dest]->getAuxValue(); int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient)); items[dest]->setAuxValue(newBrew); } else if (isWater && items[dest] != nullptr && items[dest]->id == Item::glassBottle_Id) { items[dest] = std::shared_ptr( new ItemInstance(Item::potion)); } } } if (Item::items[ingredient->id]->hasCraftingRemainingItem()) { items[INGREDIENT_SLOT] = std::shared_ptr(new ItemInstance( Item::items[ingredient->id]->getCraftingRemainingItem())); } else { items[INGREDIENT_SLOT]->count--; if (items[INGREDIENT_SLOT]->count <= 0) { items[INGREDIENT_SLOT] = nullptr; } } } int BrewingStandTileEntity::applyIngredient( int currentBrew, std::shared_ptr ingredient) { if (ingredient == nullptr) { return currentBrew; } if (!PotionBrewing::SIMPLIFIED_BREWING) { #if !(_SIMPLIFIED_BREWING) // 4J Stu - SIMPLIFIED_BREWING is on, so we never use this if (ingredient->id == Item::bucket_water_Id) { return PotionBrewing::applyBrew(currentBrew, PotionBrewing::MOD_WATER); } if (ingredient->id == Item::netherwart_seeds_Id) { return PotionBrewing::stirr(currentBrew); } #endif } if (Item::items[ingredient->id]->hasPotionBrewingFormula()) { return PotionBrewing::applyBrew( currentBrew, Item::items[ingredient->id]->getPotionBrewingFormula()); } return currentBrew; } void BrewingStandTileEntity::load(CompoundTag* base) { TileEntity::load(base); ListTag* inventoryList = (ListTag*)base->getList(L"Items"); delete[] items.data; items = ItemInstanceArray(getContainerSize()); for (int i = 0; i < inventoryList->size(); i++) { CompoundTag* tag = inventoryList->get(i); int slot = tag->getByte(L"Slot"); if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); } brewTime = base->getShort(L"BrewTime"); if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); } void BrewingStandTileEntity::save(CompoundTag* base) { TileEntity::save(base); base->putShort(L"BrewTime", (short)(brewTime)); ListTag* listTag = new ListTag(); for (int i = 0; i < items.length; i++) { if (items[i] != nullptr) { CompoundTag* tag = new CompoundTag(); tag->putByte(L"Slot", (uint8_t)i); items[i]->save(tag); listTag->add(tag); } } base->put(L"Items", listTag); if (hasCustomName()) base->putString(L"CustomName", name); } std::shared_ptr BrewingStandTileEntity::getItem( unsigned int slot) { if (slot >= 0 && slot < items.length) { return items[slot]; } return nullptr; } std::shared_ptr BrewingStandTileEntity::removeItem( unsigned int slot, int count) { // 4J Stu - Changed the implementation of this function to be the same as // ChestTileEntity to enable the "Pickup Half" option on the ingredients // slot Fix for #65373 - TU8: Content: UI: Command "Take Half" in the // Brewing Stand interface doesn't work as intended. if (slot >= 0 && slot < items.length && items[slot] != nullptr) { if (items[slot]->count <= count) { std::shared_ptr item = items[slot]; items[slot] = nullptr; this->setChanged(); // 4J Stu - Fix for duplication glitch if (item->count <= 0) return nullptr; return item; } else { std::shared_ptr i = items[slot]->remove(count); if (items[slot]->count == 0) items[slot] = nullptr; this->setChanged(); // 4J Stu - Fix for duplication glitch if (i->count <= 0) return nullptr; return i; } } return nullptr; } std::shared_ptr BrewingStandTileEntity::removeItemNoUpdate( int slot) { if (slot >= 0 && slot < items.length) { std::shared_ptr item = items[slot]; items[slot] = nullptr; return item; } return nullptr; } void BrewingStandTileEntity::setItem(unsigned int slot, std::shared_ptr item) { if (slot >= 0 && slot < items.length) { items[slot] = item; } } int BrewingStandTileEntity::getMaxStackSize() { // this value is not used for the potion slots return 64; } bool BrewingStandTileEntity::stillValid(std::shared_ptr player) { if (level->getTileEntity(x, y, z) != shared_from_this()) return false; if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; return true; } void BrewingStandTileEntity::startOpen() {} void BrewingStandTileEntity::stopOpen() {} bool BrewingStandTileEntity::canPlaceItem(int slot, std::shared_ptr item) { if (slot == INGREDIENT_SLOT) { if (PotionBrewing::SIMPLIFIED_BREWING) { return Item::items[item->id]->hasPotionBrewingFormula(); } else { return Item::items[item->id]->hasPotionBrewingFormula() || item->id == Item::netherwart_seeds_Id || item->id == Item::bucket_water_Id; } } return item->id == Item::potion_Id || item->id == Item::glassBottle_Id; } void BrewingStandTileEntity::setBrewTime(int value) { brewTime = value; } int BrewingStandTileEntity::getPotionBits() { int newCount = 0; for (int potion = 0; potion < 3; potion++) { if (items[potion] != nullptr) { newCount |= (1 << potion); } } return newCount; } intArray BrewingStandTileEntity::getSlotsForFace(int face) { if (face == Facing::UP) { return SLOTS_FOR_UP; } return SLOTS_FOR_OTHER_FACES; } bool BrewingStandTileEntity::canPlaceItemThroughFace( int slot, std::shared_ptr item, int face) { return canPlaceItem(slot, item); } bool BrewingStandTileEntity::canTakeItemThroughFace( int slot, std::shared_ptr item, int face) { return true; } // 4J Added std::shared_ptr BrewingStandTileEntity::clone() { std::shared_ptr result = std::shared_ptr(new BrewingStandTileEntity()); TileEntity::clone(result); result->brewTime = brewTime; result->lastPotionCount = lastPotionCount; result->ingredientId = ingredientId; for (unsigned int i = 0; i < items.length; i++) { if (items.data[i] != nullptr) { result->items.data[i] = ItemInstance::clone(items.data[i]); } } return result; }