#include "CraftingStorage.h" #include #include "Game.h" #include "Inventory.h" #include "Item.h" #include "RecipieList.h" #include "RecipieLoader.h" #undef min #undef max BasicShapedCrafter::BasicShapedCrafter( int width, int height, Inventory* zInventory, Framework::Text recipieList) : zInventory(zInventory), currentRecipie(0), recipieList(recipieList), width(width), height(height) { for (int i = 0; i < width * height; i++) { ItemSlot* slot = new ItemSlot("CraftingGrid", 1, std::numeric_limits::max(), std::numeric_limits::max(), INSIDE, INSIDE, 0); zInventory->addSlot(slot); craftingInput.add(slot); } std::function onChange = [this, recipieList]( ItemSlot* zSlot, Direction dir, const Item* zItem, int count) { if (!zSlot->getName().istGleich("CraftingGrid")) return; calculateOutputPreview(); }; zInventory->registerAfterPullStackCall(onChange); zInventory->registerAfterPushStackCall(onChange); zInventory->registerObserverAddedCall( [this](Entity* zSource, Framework::Text id) { Recipie* old = currentRecipie; calculateOutputPreview(); if (old == currentRecipie) { NetworkMessage* message = new NetworkMessage(); getOutputPreview(message); message->addressUIElement(id); Game::INSTANCE->sendMessage(message, zSource); } }); } void BasicShapedCrafter::getOutputPreview(NetworkMessage* zMessage) { if (currentRecipie) { Framework::Array output = currentRecipie->getOutput(); Framework::InMemoryBuffer buffer; int count = 0; for (const ItemInfo& slot : output) { count++; int itemCount = slot.count; buffer.schreibe((char*)&itemCount, 4); if (itemCount > 0) { float f = slot.hp; buffer.schreibe((char*)&f, 4); f = slot.maxHp; buffer.schreibe((char*)&f, 4); f = slot.durability; buffer.schreibe((char*)&f, 4); f = slot.maxDurability; buffer.schreibe((char*)&f, 4); int id = slot.type; buffer.schreibe((char*)&id, 4); } } char* msg = new char[5 + buffer.getSize()]; msg[0] = 100; // set crafting result *(int*)(msg + 1) = count; buffer.lese(msg + 5, (int)buffer.getSize()); zMessage->setMessage(msg, 5 + (int)buffer.getSize()); } else { char* msg = new char[5]; msg[0] = 100; // set crafting result *(int*)(msg + 1) = 0; zMessage->setMessage(msg, 5); } } bool BasicShapedCrafter::isAllAvailable( Framework::RCArray& inputs, int width, int height) { for (int x = 0; x <= this->width - width; x++) { for (int y = 0; y <= this->height - height; y++) { bool wrong = 0; for (int w = 0; w < width; w++) { for (int h = 0; h < height; h++) { RecipieInput* i = inputs.z(h * width + w); ItemSlot* s = craftingInput.get((h + y) * this->width + (x + w)); const Item* item = 0; if (s && s->zStack() && s->zStack()->getSize() >= i->getAmount()) item = s->zStack()->zItem(); wrong |= (item && !i->zFilter()) || (!item && i->zFilter()); wrong |= item && i->zFilter() && !i->zFilter()->matchItem(item); if (wrong) break; } if (wrong) break; } if (!wrong) { int i = 0; for (ItemSlot* slot : craftingInput) { int w = i % this->width; int h = i / this->width; if ((w < x || w >= x + width || h < y || h >= y + height) && slot->zStack()) return 0; // more items then needed are in crafting grid i++; } return 1; } } } return 0; } bool BasicShapedCrafter::isAllAvailable( Framework::RCArray& inputs) { bool* used = new bool[craftingInput.getEintragAnzahl()]; memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl()); for (RecipieInput* input : inputs) { bool found = 0; for (int i = 0; i < craftingInput.getEintragAnzahl(); i++) { if (used[i]) continue; ItemSlot* slot = craftingInput.get(i); if (slot && slot->zStack() && slot->zStack()->getSize() >= input->getAmount() && slot->zStack()->zItem() && input->zFilter()->matchItem(slot->zStack()->zItem())) { found = 1; used[i] = 1; break; } } if (!found) { delete[] used; return 0; } } delete[] used; return 1; } bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount) { ItemStack* stack = new ItemStack(zItem->zItemType()->cloneItem(zItem), amount); int addable = zInventory->numberOfAddableItems(stack, NO_DIRECTION); stack->release(); return addable >= amount; } bool BasicShapedCrafter::consume( Framework::RCArray& inputs, int width, int height) { int beginX = this->width; int beginY = this->height; SourceSlotBlacklistFilter otherSlotsSource; TargetSlotBlacklistFilter otherSlotsTarget; for (int i = 0; i < craftingInput.getEintragAnzahl(); i++) { if (!craftingInput.get(i)->isEmpty()) { int x = i % this->width; int y = i / this->width; beginX = MIN(beginX, x); beginY = MIN(beginY, y); } otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId()); otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId()); } for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { ItemSlot* target = craftingInput.get((y + beginY) * this->width + x + beginX); ItemStack* stack = zInventory->takeItemsOut( target, target->getNumberOfItems(), INSIDE); if (stack) { if (stack->getSize() > inputs.z(y * width + x)->getAmount()) { ItemStack* overflow = stack->split(stack->getSize() - inputs.z(y * width + x)->getAmount()); zInventory->unsaveAddItem( overflow, INSIDE, &otherSlotsTarget); if (overflow->getSize() > 0) { Game::INSTANCE->spawnItem(zInventory->getLocation(), zInventory->getDimensionId(), overflow); } else { overflow->release(); } } if (stack->getSize() > 0 && stack->zItem()) { ItemModifier* m = inputs.z(y * width + x)->zModifier(); if (m) m->applyOn((Item*)stack->zItem()); } if (stack->zItem()->getHp() == 0) stack->release(); else if (stack->zItem()->getDurability() == 0) { Item* broken = stack->zItem()->zItemType()->breakItem( stack->zItem()); if (broken) { ItemStack* brokenStack = new ItemStack(broken, stack->getSize()); zInventory->unsaveAddItem( brokenStack, INSIDE, &otherSlotsTarget); if (brokenStack->getSize() > 0) { Game::INSTANCE->spawnItem(zInventory->getLocation(), zInventory->getDimensionId(), brokenStack); } else { brokenStack->release(); } } stack->release(); } else { zInventory->addItems(target, stack, INSIDE); if (stack->getSize() > 0) { Game::INSTANCE->spawnItem(zInventory->getLocation(), zInventory->getDimensionId(), stack); } else { stack->release(); } } } ItemFilter* f = inputs.z(y * width + x)->zFilter(); if (f) { if (target->isEmpty()) { Framework::RCArray filters; filters.add(dynamic_cast(f->getThis())); filters.add( dynamic_cast(otherSlotsSource.getThis())); Framework::Array tmp; tmp.add(target); CombinedItemFilter combinedFilter( filters, [](bool a, bool b) { return a && b; }); zInventory->localTransaction( 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE); } } } } return 1; } bool BasicShapedCrafter::consume(Framework::RCArray& inputs) { SourceSlotBlacklistFilter otherSlotsSource; TargetSlotBlacklistFilter otherSlotsTarget; for (int i = 0; i < craftingInput.getEintragAnzahl(); i++) { otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId()); otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId()); } bool* used = new bool[craftingInput.getEintragAnzahl()]; memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl()); for (int i = 0; i < inputs.getEintragAnzahl(); i++) { for (int j = 0; j < craftingInput.getEintragAnzahl(); j++) { if (used[j]) continue; ItemSlot* target = craftingInput.get(j); if (target && target->zStack() && target->zStack()->getSize() >= inputs.z(i)->getAmount() && target->zStack()->zItem() && inputs.z(i)->zFilter()->matchItem(target->zStack()->zItem())) { used[i] = 1; ItemStack* stack = zInventory->takeItemsOut( target, target->getNumberOfItems(), INSIDE); if (stack) { if (stack->getSize() > inputs.z(i)->getAmount()) { ItemStack* overflow = stack->split( stack->getSize() - inputs.z(i)->getAmount()); zInventory->unsaveAddItem( overflow, INSIDE, &otherSlotsTarget); if (overflow->getSize() > 0) { Game::INSTANCE->spawnItem(zInventory->getLocation(), zInventory->getDimensionId(), overflow); } else { overflow->release(); } } if (stack->getSize() > 0 && stack->zItem()) { ItemModifier* m = inputs.z(i)->zModifier(); if (m) m->applyOn((Item*)stack->zItem()); } if (stack->zItem()->getHp() == 0) stack->release(); else if (stack->zItem()->getDurability() == 0) { Item* broken = stack->zItem()->zItemType()->breakItem( stack->zItem()); if (broken) { ItemStack* brokenStack = new ItemStack(broken, stack->getSize()); zInventory->unsaveAddItem( brokenStack, INSIDE, &otherSlotsTarget); if (brokenStack->getSize() > 0) { Game::INSTANCE->spawnItem( zInventory->getLocation(), zInventory->getDimensionId(), brokenStack); } else { brokenStack->release(); } } stack->release(); } else { zInventory->addItems(target, stack, INSIDE); if (stack->getSize() > 0) { Game::INSTANCE->spawnItem(zInventory->getLocation(), zInventory->getDimensionId(), stack); } else { stack->release(); } } } ItemFilter* f = inputs.z(i)->zFilter(); if (f) { if (target->isEmpty()) { Framework::RCArray filters; filters.add(dynamic_cast(f->getThis())); filters.add(dynamic_cast( otherSlotsSource.getThis())); Framework::Array tmp; tmp.add(target); CombinedItemFilter combinedFilter( filters, [](bool a, bool b) { return a && b; }); zInventory->localTransaction( 0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE); } } break; } } } delete[] used; return 1; } void BasicShapedCrafter::addCraftingResult(ItemStack* stack) { TargetSlotBlacklistFilter otherSlotsTarget; for (int i = 0; i < craftingInput.getEintragAnzahl(); i++) otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId()); zInventory->unsaveAddItem(stack, NO_DIRECTION, &otherSlotsTarget); } void BasicShapedCrafter::applyCurrentRecipie() { if (currentRecipie && currentRecipie->testApplicability(this)) currentRecipie->apply(this); } void BasicShapedCrafter::calculateOutputPreview() { RecipieList* recipies = Game::INSTANCE->zRecipies()->zRecipieList(recipieList); if (recipies) { Recipie* recipie = recipies->zFirstRecipie(this); if (recipie != currentRecipie) { currentRecipie = recipie; NetworkMessage* message = new NetworkMessage(); getOutputPreview(message); zInventory->notifyObservers(message); } } }