浏览代码

add possibility to recuest crafting recipies for a specific item type

Kolja Strohm 1 年之前
父节点
当前提交
749e40e503

+ 1 - 1
FactoryCraft/BasicBlock.cpp

@@ -49,7 +49,7 @@ void AdditionalItemSpawningBlock::onDestroy()
                                                      0.5f, 0.5f, 0.5f),
                                   getDimensionId(),
                                   Game::INSTANCE->getNextEntityId());
-                    itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION);
+                    itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
                     spawnedItems->release();
                     Game::INSTANCE->requestWorldUpdate(
                         new AddEntityUpdate(itemEntity, getDimensionId()));

+ 1 - 1
FactoryCraft/Block.cpp

@@ -69,7 +69,7 @@ void Block::onDestroy()
                           Game::INSTANCE->getNextEntityId());
             ItemStack* stack
                 = new ItemStack(blockItem, 1, blockItem->getMaxStackSize());
-            itemEntity->unsaveAddItem(stack, NO_DIRECTION);
+            itemEntity->unsaveAddItem(stack, NO_DIRECTION, 0);
             stack->release();
             Game::INSTANCE->requestWorldUpdate(
                 new AddEntityUpdate(itemEntity, dimensionId));

+ 173 - 18
FactoryCraft/CraftingStorage.cpp

@@ -38,7 +38,7 @@ BasicShapedCrafter::BasicShapedCrafter(
     zInventory->registerAfterPushStackCall(onChange);
     zInventory->registerObserverAddedCall(
         [this](Entity* zSource, Framework::Text id) {
-            ShapedRecipie* old = currentRecipie;
+            Recipie* old = currentRecipie;
             calculateOutputPreview();
             if (old == currentRecipie)
             {
@@ -91,8 +91,10 @@ void BasicShapedCrafter::getOutputPreview(NetworkMessage* zMessage)
     }
 }
 
-bool BasicShapedCrafter::isAllAvailable(
-    Framework::RCArray<ItemFilter>& filters, int width, int height)
+bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters,
+    Framework::Array<int>& inputAmount,
+    int width,
+    int height)
 {
     for (int x = 0; x <= this->width - width; x++)
     {
@@ -107,7 +109,10 @@ bool BasicShapedCrafter::isAllAvailable(
                     ItemSlot* s
                         = craftingInput.get((h + y) * this->width + (x + w));
                     const Item* item = 0;
-                    if (s && s->zStack()) item = s->zStack()->zItem();
+                    if (s && s->zStack()
+                        && s->zStack()->getSize() >= inputAmount.get(
+                               (h + y) * this->width + (x + w)))
+                        item = s->zStack()->zItem();
                     wrong |= (item && !f) || (!item && f);
                     wrong |= item && f && !f->matchItem(item);
                     if (wrong) break;
@@ -133,6 +138,40 @@ bool BasicShapedCrafter::isAllAvailable(
     return 0;
 }
 
+bool BasicShapedCrafter::isAllAvailable(
+    Framework::RCArray<ItemFilter>& filters, Framework::Array<int>& inputAmount)
+{
+    bool* used = new bool[craftingInput.getEintragAnzahl()];
+    memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
+    int index = 0;
+    for (ItemFilter* filter : filters)
+    {
+        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() >= inputAmount.get(index)
+                && slot->zStack()->zItem()
+                && filter->matchItem(slot->zStack()->zItem()))
+            {
+                found = 1;
+                used[i] = 1;
+                break;
+            }
+        }
+        if (!found)
+        {
+            delete[] used;
+            return 0;
+        }
+        index++;
+    }
+    delete[] used;
+    return 1;
+}
+
 bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
 {
     ItemStack* stack
@@ -143,13 +182,15 @@ bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
 }
 
 bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
-    Framework::RCArray<ItemModifier>& modfiers,
+    Framework::RCArray<ItemModifier>& modifiers,
+    Framework::Array<int>& inputAmount,
     int width,
     int height)
 {
     int beginX = this->width;
     int beginY = this->height;
-    SourceSlotBlacklistFilter otherSlots;
+    SourceSlotBlacklistFilter otherSlotsSource;
+    TargetSlotBlacklistFilter otherSlotsTarget;
     for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
     {
         if (!craftingInput.get(i)->isEmpty())
@@ -159,7 +200,8 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
             beginX = MIN(beginX, x);
             beginY = MIN(beginY, y);
         }
-        otherSlots.addBlackListSlotId(craftingInput.get(i)->getId());
+        otherSlotsSource.addBlackListSlotId(craftingInput.get(i)->getId());
+        otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
     }
     for (int x = 0; x < width; x++)
     {
@@ -167,12 +209,27 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
         {
             ItemSlot* target
                 = craftingInput.get((y + beginY) * this->width + x + beginX);
-            ItemStack* stack = zInventory->takeItemsOut(target, 1, INSIDE);
+            ItemStack* stack = zInventory->takeItemsOut(
+                target, target->getNumberOfItems(), INSIDE);
             if (stack)
             {
+                if (stack->getSize()
+                    > inputAmount.get(y * width + x))
+                {
+                    ItemStack* overflow = stack->split(
+                        stack->getSize()
+                        - inputAmount.get(y * width + x));
+                    zInventory->unsaveAddItem(
+                        overflow, INSIDE, &otherSlotsTarget);
+                    if (overflow->getSize() > 0)
+                    {
+                        // TODO: drop items
+                    }
+                    overflow->release();
+                }
                 if (stack->getSize() > 0 && stack->zItem())
                 {
-                    ItemModifier* m = modfiers.z(y * width + x);
+                    ItemModifier* m = modifiers.z(y * width + x);
                     if (m) m->applyOn((Item*)stack->zItem());
                 }
                 if (stack->zItem()->getHp() == 0)
@@ -184,8 +241,10 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                     stack->release();
                     if (broken)
                     {
-                        ItemStack* brokenStack = new ItemStack(broken, 1);
-                        zInventory->unsaveAddItem(brokenStack, INSIDE);
+                        ItemStack* brokenStack
+                            = new ItemStack(broken, stack->getSize());
+                        zInventory->unsaveAddItem(
+                            brokenStack, INSIDE, &otherSlotsTarget);
                         // TODO: if brokenStack is not empty spawn an item
                         // entity
                         brokenStack->release();
@@ -193,8 +252,6 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                 }
                 else
                 {
-                    // TODO: transfer all items from target to other slots or
-                    // drop them
                     zInventory->addItems(target, stack, INSIDE);
                     // TODO: if stack is not empty spawn an item entity
                 }
@@ -208,7 +265,7 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                     tmp.add(target);
                     CombinedItemFilter combinedFilter(
                         dynamic_cast<ItemFilter*>(f->getThis()),
-                        dynamic_cast<ItemFilter*>(otherSlots.getThis()),
+                        dynamic_cast<ItemFilter*>(otherSlotsSource.getThis()),
                         [](bool a, bool b) { return a && b; });
                     zInventory->localTransaction(
                         0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
@@ -219,9 +276,107 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
     return 1;
 }
 
+bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
+    Framework::RCArray<ItemModifier>& modifiers,
+    Framework::Array<int>& inputAmount)
+{
+    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 < filters.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() >= inputAmount.get(i)
+                && target->zStack()->zItem()
+                && filters.z(i)->matchItem(target->zStack()->zItem()))
+            {
+                used[i] = 1;
+                ItemStack* stack = zInventory->takeItemsOut(
+                    target, target->getNumberOfItems(), INSIDE);
+                if (stack)
+                {
+                    if (stack->getSize() > inputAmount.get(i))
+                    {
+                        ItemStack* overflow = stack->split(
+                            stack->getSize() - inputAmount.get(i));
+                        zInventory->unsaveAddItem(
+                            overflow, INSIDE, &otherSlotsTarget);
+                        if (overflow->getSize() > 0)
+                        {
+                            // TODO: drop items
+                        }
+                        overflow->release();
+                    }
+                    if (stack->getSize() > 0 && stack->zItem())
+                    {
+                        ItemModifier* m = modifiers.z(i);
+                        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());
+                        stack->release();
+                        if (broken)
+                        {
+                            ItemStack* brokenStack
+                                = new ItemStack(broken, stack->getSize());
+                            zInventory->unsaveAddItem(
+                                brokenStack, INSIDE, &otherSlotsTarget);
+                            // TODO: if brokenStack is not empty spawn an item
+                            // entity
+                            brokenStack->release();
+                        }
+                    }
+                    else
+                    {
+                        zInventory->addItems(target, stack, INSIDE);
+                        // TODO: if stack is not empty spawn an item entity
+                    }
+                }
+                ItemFilter* f = filters.z(i);
+                if (f)
+                {
+                    if (target->isEmpty())
+                    {
+                        Framework::Array<ItemSlot*> tmp;
+                        tmp.add(target);
+                        CombinedItemFilter combinedFilter(
+                            dynamic_cast<ItemFilter*>(f->getThis()),
+                            dynamic_cast<ItemFilter*>(
+                                otherSlotsSource.getThis()),
+                            [](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)
 {
-    zInventory->unsaveAddItem(stack, NO_DIRECTION);
+    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()
@@ -232,11 +387,11 @@ void BasicShapedCrafter::applyCurrentRecipie()
 
 void BasicShapedCrafter::calculateOutputPreview()
 {
-    ShapedRecipieList* recipies
-        = Game::INSTANCE->getRecipies().zShapedRecipieList(recipieList);
+    RecipieList* recipies
+        = Game::INSTANCE->getRecipies().zRecipieList(recipieList);
     if (recipies)
     {
-        ShapedRecipie* recipie = recipies->zFirstRecipie(this);
+        Recipie* recipie = recipies->zFirstRecipie(this);
         if (recipie != currentRecipie)
         {
             currentRecipie = recipie;

+ 15 - 6
FactoryCraft/CraftingStorage.h

@@ -15,24 +15,26 @@ public:
         = 0;
     virtual bool hasFreeSpace(const Item* zItem, int amount) = 0;
     virtual bool consume(Framework::RCArray<ItemFilter>& filters,
+        Framework::RCArray<ItemModifier>& modifiers,
         Framework::Array<int>& inputAmount)
         = 0;
     virtual void addCraftingResult(ItemStack* stack) = 0;
 };
 
-class ShapedCraftingStorage
+class ShapedCraftingStorage : public CraftingStorage
 {
 public:
-    virtual bool isAllAvailable(
-        Framework::RCArray<ItemFilter>& filters, int width, int height)
+    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
+        Framework::Array<int>& inputAmount,
+        int width,
+        int height)
         = 0;
-    virtual bool hasFreeSpace(const Item* zItem, int amount) = 0;
     virtual bool consume(Framework::RCArray<ItemFilter>& filters,
         Framework::RCArray<ItemModifier>& modifiers,
+        Framework::Array<int>& inputAmount,
         int width,
         int height)
         = 0;
-    virtual void addCraftingResult(ItemStack* stack) = 0;
 };
 
 class BasicShapedCrafter : public ShapedCraftingStorage
@@ -40,7 +42,7 @@ class BasicShapedCrafter : public ShapedCraftingStorage
 private:
     Framework::Array<ItemSlot*> craftingInput;
     Inventory* zInventory;
-    ShapedRecipie* currentRecipie;
+    Recipie* currentRecipie;
     Framework::Text recipieList;
     int width;
     int height;
@@ -53,13 +55,20 @@ public:
         Inventory* zInventory,
         Framework::Text recipieList);
     virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
+        Framework::Array<int>& inputAmount,
         int width,
         int height) override;
+    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
+        Framework::Array<int>& inputAmount) override;
     virtual bool hasFreeSpace(const Item* zItem, int amount) override;
     virtual bool consume(Framework::RCArray<ItemFilter>& filters,
         Framework::RCArray<ItemModifier>& modifiers,
+        Framework::Array<int>& inputAmount,
         int width,
         int height) override;
+    virtual bool consume(Framework::RCArray<ItemFilter>& filters,
+        Framework::RCArray<ItemModifier>& modifiers,
+        Framework::Array<int>& inputAmount) override;
     virtual void addCraftingResult(ItemStack* stack) override;
     void applyCurrentRecipie();
     void calculateOutputPreview();

+ 1 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -211,6 +211,7 @@
     <ClCompile Include="NoiseInterpolator.cpp" />
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="PlayerHand.cpp" />
+    <ClCompile Include="RecipieList.cpp" />
     <ClCompile Include="RandNoise.cpp" />
     <ClCompile Include="Recipie.cpp" />
     <ClCompile Include="RecipieLoader.cpp" />

+ 3 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -473,5 +473,8 @@
     <ClCompile Include="FluidBlock.cpp">
       <Filter>world\blocks\fluids</Filter>
     </ClCompile>
+    <ClCompile Include="RecipieList.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 23 - 0
FactoryCraft/Game.cpp

@@ -260,6 +260,13 @@ void GameClient::sendTypes()
             ItemType* t = StaticRegistry<ItemType>::INSTANCE.zElement(i);
             int id = t->getId();
             client->zForegroundWriter()->schreibe((char*)&id, 4);
+            char len = (char)t->getName().getLength();
+            client->zForegroundWriter()->schreibe((char*)&len, 1);
+            client->zForegroundWriter()->schreibe(t->getName().getText(), len);
+            short tlen = (short)t->getTooltipUIML().getLength();
+            client->zForegroundWriter()->schreibe((char*)&tlen, 2);
+            client->zForegroundWriter()->schreibe(
+                t->getTooltipUIML().getText(), tlen);
             t->getModel().writeTo(client->zForegroundWriter());
         }
     }
@@ -523,6 +530,22 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
                 target->inventoryApi(zRequest, response, zOrigin->zEntity());
             break;
         }
+    case 5:
+        { // crafting uiml request
+            int id;
+            zRequest->lese((char*)&id, 4);
+            Text uiml = recipies.getCrafingUIML(
+                StaticRegistry<ItemType>::INSTANCE.zElement(id));
+            Text dialogId = "crafting_";
+            dialogId += id;
+            response->openDialog(dialogId);
+            int msgSize = 4 + uiml.getLength();
+            char* msg = new char[msgSize];
+            *(int*)msg = uiml.getLength();
+            memcpy(msg + 4, uiml.getText(), uiml.getLength());
+            response->setMessage(msg, msgSize);
+            break;
+        }
     default:
         std::cout << "received unknown api request in game with type "
                   << (int)type << "\n";

+ 1 - 1
FactoryCraft/Grass.cpp

@@ -50,7 +50,7 @@ void GrassBlock::onDestroy()
                                   + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
                               getDimensionId(),
                               Game::INSTANCE->getNextEntityId());
-                itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION);
+                itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
                 spawnedItems->release();
                 Game::INSTANCE->requestWorldUpdate(
                     new AddEntityUpdate(itemEntity, getDimensionId()));

+ 5 - 4
FactoryCraft/Inventory.cpp

@@ -546,7 +546,7 @@ void Inventory::localTransaction(Array<ItemSlot*>* zSourceSlots,
     }
 }
 
-void Inventory::addItems(ItemStack* zItems, Direction dir)
+void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
 {
     if (itemCache && zItems && zItems->getSize() > 0)
     {
@@ -554,7 +554,7 @@ void Inventory::addItems(ItemStack* zItems, Direction dir)
         for (auto targetSlot = pushSlotsOrder->begin(); targetSlot;
              targetSlot++)
         {
-            if (!targetSlot->isFull())
+            if (!targetSlot->isFull() && (!zFilter || zFilter->matchTargetSlot(targetSlot)))
             {
                 if (targetSlot->zStack())
                 {
@@ -663,9 +663,10 @@ InventoryInteraction Inventory::interactWith(
     return InventoryInteraction(this, zInventory, dir);
 }
 
-void Inventory::unsaveAddItem(ItemStack* zStack, Direction dir)
+void Inventory::unsaveAddItem(
+    ItemStack* zStack, Direction dir, ItemFilter* zFilter)
 {
-    addItems(zStack, dir);
+    addItems(zStack, dir, zFilter);
 }
 
 int Inventory::numberOfAddableItems(

+ 3 - 2
FactoryCraft/Inventory.h

@@ -88,7 +88,8 @@ protected:
     virtual void saveInventory(Framework::StreamWriter* zWriter);
     void removeObserver(Entity* zSource, Framework::Text id);
     void addObserver(Entity* zSource, Framework::Text id);
-    virtual void addItems(ItemStack* zItems, Direction dir);
+    virtual void addItems(
+        ItemStack* zItems, Direction dir, ItemFilter* zFilter);
 
 public:
     Inventory(const Framework::Vec3<float> location, bool hasInventory);
@@ -105,7 +106,7 @@ public:
     ItemStack* takeItemsOut(ItemSlot* zSlot, int count, Direction dir);
     virtual void addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir);
     InventoryInteraction interactWith(Inventory* zInventory, Direction dir);
-    void unsaveAddItem(ItemStack* zStack, Direction dir);
+    void unsaveAddItem(ItemStack* zStack, Direction dir, ItemFilter *zFilter);
     int numberOfAddableItems(const ItemStack* zStack, Direction dir) const;
     Framework::Iterator<ItemSlot*> begin();
     Framework::Iterator<ItemSlot*> end();

+ 102 - 0
FactoryCraft/ItemFilter.cpp

@@ -53,6 +53,29 @@ bool CombinedItemFilter::matchTargetSlot(ItemSlot* zSlot) const
     return op(filterA->matchTargetSlot(zSlot), filterB->matchTargetSlot(zSlot));
 }
 
+Framework::Text CombinedItemFilter::getImageUIML() const
+{
+    return filterA->getImageUIML() + filterB->getImageUIML();
+}
+
+Framework::Text CombinedItemFilter::getLogicUIML() const
+{
+    Framework::Text result = "<operator result_0_0=\"";
+    result += op(0, 0);
+    result += "\" result_0_1=\"";
+    result += op(0, 1);
+    result += "\" result_1_0=\"";
+    result += op(1, 0);
+    result += "\" result_1_1=\"";
+    result += op(1, 1);
+    result += ">";
+    result += filterA->getLogicUIML();
+    result += filterB->getLogicUIML();
+    result += "</operator>";
+    return result;
+}
+
+
 AnyItemFilter::AnyItemFilter()
     : ItemFilter()
 {}
@@ -62,6 +85,16 @@ bool AnyItemFilter::matchItem(const Item* zItem) const
     return true;
 }
 
+Framework::Text AnyItemFilter::getImageUIML() const
+{
+    return "<img str=\"bilder/gui_icons.ltdb/anyItem.png\"/>";
+}
+
+Framework::Text AnyItemFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
+}
+
 TypeItemFilter::TypeItemFilter(const ItemType* zType)
     : ItemFilter(),
       zType(zType)
@@ -72,6 +105,22 @@ bool TypeItemFilter::matchItem(const Item* zItem) const
     return zItem->zItemType() == zType;
 }
 
+Framework::Text TypeItemFilter::getImageUIML() const
+{
+    Framework::Text result = "<img itemType=\"";
+    result += zType->getId();
+    result += "\"/>";
+    return result;
+}
+
+Framework::Text TypeItemFilter::getLogicUIML() const
+{
+    Framework::Text result = "<attribute name=\"Type\" operator=\"=\" value=\"";
+    result += zType->getName();
+    result += "\"/>";
+    return result;
+}
+
 SpecificSlotFilter::SpecificSlotFilter(int sourceSlotId, int targetSlotId)
     : ItemFilter(),
       sourceSlotId(sourceSlotId),
@@ -88,6 +137,16 @@ bool SpecificSlotFilter::matchTargetSlot(ItemSlot* zSlot) const
     return targetSlotId == zSlot->getId();
 }
 
+Framework::Text SpecificSlotFilter::getImageUIML() const
+{
+    return "<img str=\"bilder/gui_icons.ltdb/anyItem.png\"/>";
+}
+
+Framework::Text SpecificSlotFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
+}
+
 SourceSlotBlacklistFilter::SourceSlotBlacklistFilter()
     : ItemFilter()
 {}
@@ -109,4 +168,47 @@ bool SourceSlotBlacklistFilter::matchSourceSlot(ItemSlot* zSlot) const
 bool SourceSlotBlacklistFilter::matchTargetSlot(ItemSlot* zSlot) const
 {
     return 1;
+}
+
+Framework::Text SourceSlotBlacklistFilter::getImageUIML() const
+{
+    return "<img str=\"bilder/gui_icons.ltdb/anyItem.png\"/>";
+}
+
+Framework::Text SourceSlotBlacklistFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
+}
+
+TargetSlotBlacklistFilter::TargetSlotBlacklistFilter()
+    : ItemFilter()
+{}
+
+void TargetSlotBlacklistFilter::addBlackListSlotId(int id)
+{
+    blackList.add(id);
+}
+
+bool TargetSlotBlacklistFilter::matchSourceSlot(ItemSlot* zSlot) const
+{
+    return 1;
+}
+
+bool TargetSlotBlacklistFilter::matchTargetSlot(ItemSlot* zSlot) const
+{
+    for (int black : blackList)
+    {
+        if (black == zSlot->getId()) return 0;
+    }
+    return 1;
+}
+
+Framework::Text TargetSlotBlacklistFilter::getImageUIML() const
+{
+    return "<img str=\"bilder/gui_icons.ltdb/anyItem.png\"/>";
+}
+
+Framework::Text TargetSlotBlacklistFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
 }

+ 26 - 0
FactoryCraft/ItemFilter.h

@@ -15,6 +15,8 @@ public:
     virtual bool matchItem(const Item* zItem) const;
     virtual bool matchSourceSlot(ItemSlot* zSlot) const;
     virtual bool matchTargetSlot(ItemSlot* zSlot) const;
+    virtual Framework::Text getImageUIML() const = 0;
+    virtual Framework::Text getLogicUIML() const = 0;
 };
 
 class CombinedItemFilter : public ItemFilter
@@ -32,6 +34,8 @@ public:
     bool matchItem(const Item* zItem) const override;
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
 };
 
 class AnyItemFilter : public ItemFilter
@@ -39,6 +43,8 @@ class AnyItemFilter : public ItemFilter
 public:
     AnyItemFilter();
     bool matchItem(const Item* zItem) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
 };
 
 class TypeItemFilter : public ItemFilter
@@ -49,6 +55,8 @@ private:
 public:
     TypeItemFilter(const ItemType* zType);
     bool matchItem(const Item* zItem) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
 };
 
 class SpecificSlotFilter : public ItemFilter
@@ -61,6 +69,8 @@ public:
     SpecificSlotFilter(int sourceSlotId, int targetSlotId);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
 };
 
 class SourceSlotBlacklistFilter : public ItemFilter
@@ -73,4 +83,20 @@ public:
     void addBlackListSlotId(int id);
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
+};
+
+class TargetSlotBlacklistFilter : public ItemFilter
+{
+private:
+    Framework::Array<int> blackList;
+
+public:
+    TargetSlotBlacklistFilter();
+    void addBlackListSlotId(int id);
+    bool matchSourceSlot(ItemSlot* zSlot) const override;
+    bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getImageUIML() const override;
+    Framework::Text getLogicUIML() const override;
 };

+ 7 - 0
FactoryCraft/ItemType.cpp

@@ -18,6 +18,8 @@ ItemType::ItemType(int id,
       brokenTypeId(brokenTypeId),
       model(model)
 {
+    tooltipUIML = Framework::Text("<tip><text width=\"auto\" height=\"auto\">")
+                + name + "</text></tip>";
     StaticRegistry<ItemType>::INSTANCE.registerT(this, id);
 }
 
@@ -83,6 +85,11 @@ const Framework::Text& ItemType::getName() const
     return name;
 }
 
+const Framework::Text& ItemType::getTooltipUIML() const
+{
+    return tooltipUIML;
+}
+
 const ItemType* ItemType::zBrokenItemType() const
 {
     return StaticRegistry<ItemType>::INSTANCE.zElement(brokenTypeId);

+ 2 - 0
FactoryCraft/ItemType.h

@@ -33,6 +33,7 @@ class ItemType : public virtual Framework::ReferenceCounter
 protected:
     const int id;
     const Framework::Text name;
+    Framework::Text tooltipUIML;
     ItemSkillLevelUpRule* levelUpRule;
     int brokenTypeId;
     const ModelInfo model;
@@ -57,6 +58,7 @@ public:
 
     int getId() const;
     const Framework::Text& getName() const;
+    const Framework::Text& getTooltipUIML() const;
     const ItemType* zBrokenItemType() const;
     virtual Item* createItem() const = 0;
     virtual ItemStack* createItemStack(int size) const;

+ 2 - 2
FactoryCraft/Player.cpp

@@ -113,7 +113,7 @@ void Player::useItemSlot(ItemSlot* zSlot)
                         ItemStack* oldItems = takeItemsOut(
                             zSlot, zSlot->zStack()->getSize(), NO_DIRECTION);
                         addItems(zSlot, stack, NO_DIRECTION);
-                        addItems(oldItems, NO_DIRECTION);
+                        addItems(oldItems, NO_DIRECTION, 0);
                         if (oldItems->getSize() > 0)
                         {
                             // TODO: drop remaining items
@@ -148,7 +148,7 @@ void Player::useItemSlot(ItemSlot* zSlot)
                         if (broken)
                         {
                             stack->addToStack(broken);
-                            addItems(stack, NO_DIRECTION);
+                            addItems(stack, NO_DIRECTION, 0);
                             if (stack->getSize() > 0)
                             {
                                 // TODO: drop remaining items

+ 146 - 44
FactoryCraft/Recipie.cpp

@@ -1,24 +1,62 @@
 #include "Recipie.h"
 
 #include "CraftingStorage.h"
+#include "Item.h"
 
 Recipie::Recipie()
     : ReferenceCounter()
 {}
 
-void Recipie::addIngredient(ItemFilter* filter, int amount)
-{
-    filters.add(filter);
-    inputAmount.add(amount);
-}
-
 void Recipie::addOutput(Item* item, int amount)
 {
     outputs.add(item);
     outputAmount.add(amount);
 }
 
-bool Recipie::testApplicability(CraftingStorage* zStorage)
+Framework::Array<ItemInfo> Recipie::getOutput(CraftingStorage* zStorage) const
+{
+    Framework::Array<ItemInfo> result;
+    int index = 0;
+    for (const Item* output : outputs)
+    {
+        ItemInfo info;
+        info.count = outputAmount.get(index);
+        info.type = output->zItemType()->getId();
+        info.hp = output->getHp();
+        info.durability = output->getDurability();
+        info.maxHp = output->getMaxHp();
+        info.maxDurability = output->getMaxDurability();
+        result.add(info);
+        index++;
+    }
+    return result;
+}
+
+bool Recipie::createsOutput(ItemType* zType)
+{
+    for (const Item* output : outputs)
+    {
+        if (output->zItemType() == zType)
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+UnshapedRecipie::UnshapedRecipie()
+    : Recipie()
+{}
+
+void UnshapedRecipie::addIngredient(
+    ItemFilter* filter, int amount, ItemModifier* modifier)
+{
+    filters.add(filter);
+    modifiers.add(modifier);
+    inputAmount.add(amount);
+}
+
+bool UnshapedRecipie::testApplicability(CraftingStorage* zStorage)
 {
     for (int i = 0; i < outputs.getEintragAnzahl(); i++)
     {
@@ -28,9 +66,9 @@ bool Recipie::testApplicability(CraftingStorage* zStorage)
     return zStorage->isAllAvailable(filters, inputAmount);
 }
 
-void Recipie::apply(CraftingStorage* zStorage)
+void UnshapedRecipie::apply(CraftingStorage* zStorage)
 {
-    zStorage->consume(filters, inputAmount);
+    zStorage->consume(filters, modifiers, inputAmount);
     for (int i = 0; i < outputs.getEintragAnzahl(); i++)
     {
         ItemStack* stack
@@ -41,65 +79,129 @@ void Recipie::apply(CraftingStorage* zStorage)
     }
 }
 
+Framework::Text UnshapedRecipie::getRecipieUIML()
+{
+    Framework::Text result = "<recipie type=\"unshaped\"><ingredients>";
+    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    {
+        result += "<ingredient amount=\"";
+        result += inputAmount.get(i);
+        result += "\"><images>";
+        result += filters.z(i)->getImageUIML();
+        result += "</images><logic>";
+        result += filters.z(i)->getLogicUIML();
+        result += "</logic></ingredient>";
+        // todo: add modifiers
+    }
+    result += "</ingredient><outputs>";
+    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    {
+        result += "<output amount=\"";
+        result += outputAmount.get(i);
+        result += "\" itemType=\"";
+        result += outputs.z(i)->zItemType()->getId();
+        result += "\" hp=\"";
+        result += outputs.z(i)->getHp();
+        result += "\" durability=\"";
+        result += outputs.z(i)->getDurability();
+        result += "\" maxHp=\"";
+        result += outputs.z(i)->getMaxHp();
+        result += "\" maxDurability=\"";
+        result += outputs.z(i)->getMaxDurability();
+        result += "\">";
+        result += outputs.z(i)->getTooltipUIML();
+        result += "</output>";
+    }
+    result += "</output></recipie>";
+    return result;
+}
+
 ShapedRecipie::ShapedRecipie(int width, int height)
     : ReferenceCounter(),
       width(width),
-      height(height),
-      output(0),
-      outputAmount(0)
+      height(height)
 {
     for (int i = 0; i < width * height; i++)
     {
         filters.add(0);
+        inputAmount.add(0);
         modifiers.add(0);
     }
 }
 
-ShapedRecipie::~ShapedRecipie()
-{
-    if (output) output->release();
-}
-
 void ShapedRecipie::setIngredient(
     int x, int y, ItemFilter* filter, ItemModifier* modifier)
 {
     filters.set(filter, width * y + x);
+    inputAmount.set(1, width * y + x); // TODO: make this configurable
     modifiers.set(modifier, width * y + x);
 }
 
-void ShapedRecipie::setOutput(Item* item, int amount)
+bool ShapedRecipie::testApplicability(CraftingStorage* zStorage)
 {
-    if (output) output->release();
-    output = item;
-    outputAmount = amount;
-}
-
-bool ShapedRecipie::testApplicability(ShapedCraftingStorage* zStorage)
-{
-    return zStorage->isAllAvailable(filters, width, height)
-        && zStorage->hasFreeSpace(output, outputAmount);
+    ShapedCraftingStorage* zShapedStorage
+        = dynamic_cast<ShapedCraftingStorage*>(zStorage);
+    if (!zShapedStorage) return 0;
+    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    {
+        if (!zShapedStorage->hasFreeSpace(outputs.z(i), outputAmount.get(i)))
+            return 0;
+    }
+    return zShapedStorage->isAllAvailable(filters, inputAmount, width, height);
 }
 
-void ShapedRecipie::apply(ShapedCraftingStorage* zStorage)
+void ShapedRecipie::apply(CraftingStorage* zStorage)
 {
-    zStorage->consume(filters, modifiers, width, height);
-    ItemStack* stack
-        = new ItemStack(output->zItemType()->cloneItem(output), outputAmount);
-    zStorage->addCraftingResult(stack);
-    stack->release();
+    ShapedCraftingStorage* zShapedStorage
+        = dynamic_cast<ShapedCraftingStorage*>(zStorage);
+    zShapedStorage->consume(filters, modifiers, inputAmount, width, height);
+    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    {
+        ItemStack* stack
+            = new ItemStack(outputs.z(i)->zItemType()->cloneItem(outputs.z(i)),
+                outputAmount.get(i));
+        zStorage->addCraftingResult(stack);
+        stack->release();
+    }
 }
 
-Framework::Array<ItemInfo> ShapedRecipie::getOutput(
-    ShapedCraftingStorage* zStorage)
+Framework::Text ShapedRecipie::getRecipieUIML()
 {
-    Framework::Array<ItemInfo> result;
-    ItemInfo info;
-    info.count = outputAmount;
-    info.type = output->zItemType()->getId();
-    info.hp = output->getHp();
-    info.durability = output->getDurability();
-    info.maxHp = output->getMaxHp();
-    info.maxDurability = output->getMaxDurability();
-    result.add(info);
+    Framework::Text result = "<recipie type=\"shaped\" width=\"";
+    result += width;
+    result += "\" height=\"";
+    result += height;
+    result += "\"><ingredients>";
+    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    {
+        result += "<ingredient amount=\"";
+        result += inputAmount.get(i);
+        result += "\"><images>";
+        result += filters.z(i)->getImageUIML();
+        result += "</images><logic>";
+        result += filters.z(i)->getLogicUIML();
+        result += "</logic></ingredient>";
+        // todo: add modifiers
+    }
+    result += "</ingredient><outputs>";
+    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    {
+        result += "<output amount=\"";
+        result += outputAmount.get(i);
+        result += "\" itemType=\"";
+        result += outputs.z(i)->zItemType()->getId();
+        result += "\" hp=\"";
+        result += outputs.z(i)->getHp();
+        result += "\" durability=\"";
+        result += outputs.z(i)->getDurability();
+        result += "\" maxHp=\"";
+        result += outputs.z(i)->getMaxHp();
+        result += "\" maxDurability=\"";
+        result += outputs.z(i)->getMaxDurability();
+        result += "\">";
+        result += outputs.z(i)->getTooltipUIML();
+        result += "</output>";
+    }
+    result += "</output></recipie>";
     return result;
 }

+ 28 - 15
FactoryCraft/Recipie.h

@@ -20,37 +20,50 @@ struct ItemInfo
 
 class Recipie : public virtual Framework::ReferenceCounter
 {
-private:
-    Framework::RCArray<ItemFilter> filters;
-    Framework::Array<int> inputAmount;
+protected:
     Framework::RCArray<Item> outputs;
     Framework::Array<int> outputAmount;
 
 public:
     Recipie();
-    void addIngredient(ItemFilter* filter, int amount);
-    void addOutput(Item* item, int amount);
-    bool testApplicability(CraftingStorage* zStorage);
-    void apply(CraftingStorage* zStorage);
+    virtual void addOutput(Item* item, int amount);
+    virtual bool testApplicability(CraftingStorage* zStorage) = 0;
+    virtual void apply(CraftingStorage* zStorage) = 0;
+    virtual Framework::Text getRecipieUIML() = 0;
+    virtual Framework::Array<ItemInfo> getOutput(
+        CraftingStorage* zStorage) const;
+    virtual bool createsOutput(ItemType* zType);
 };
 
-class ShapedRecipie : public virtual Framework::ReferenceCounter
+class UnshapedRecipie : public Recipie
 {
 private:
     Framework::RCArray<ItemFilter> filters;
     Framework::RCArray<ItemModifier> modifiers;
+    Framework::Array<int> inputAmount;
+
+public:
+    UnshapedRecipie();
+    void addIngredient(ItemFilter* filter, int amount, ItemModifier* modifier);
+    bool testApplicability(CraftingStorage* zStorage) override;
+    void apply(CraftingStorage* zStorage) override;
+    Framework::Text getRecipieUIML() override;
+};
+
+class ShapedRecipie : public Recipie
+{
+private:
+    Framework::RCArray<ItemFilter> filters;
+    Framework::RCArray<ItemModifier> modifiers;
+    Framework::Array<int> inputAmount;
     int width;
     int height;
-    Item* output;
-    int outputAmount;
 
 public:
     ShapedRecipie(int width, int height);
-    ~ShapedRecipie();
     void setIngredient(
         int x, int y, ItemFilter* filter, ItemModifier* modifier);
-    void setOutput(Item* item, int amount);
-    bool testApplicability(ShapedCraftingStorage* zStorage);
-    void apply(ShapedCraftingStorage* zStorage);
-    Framework::Array<ItemInfo> getOutput(ShapedCraftingStorage* zStorage);
+    bool testApplicability(CraftingStorage* zStorage) override;
+    void apply(CraftingStorage* zStorage) override;
+    Framework::Text getRecipieUIML() override;
 };

+ 37 - 0
FactoryCraft/RecipieList.cpp

@@ -0,0 +1,37 @@
+#include "RecipieList.h"
+
+RecipieList::RecipieList(const char* name)
+    : ReferenceCounter(),
+      name(name)
+{}
+
+void RecipieList::addRecipie(Recipie* recipie)
+{
+    recipies.add(recipie);
+}
+
+Recipie* RecipieList::zFirstRecipie(CraftingStorage* zStorage)
+{
+    for (Recipie* recipie : recipies)
+    {
+        if (recipie->testApplicability(zStorage)) return recipie;
+    }
+    return 0;
+}
+
+const Framework::Text& RecipieList::getName() const
+{
+    return name;
+}
+
+void RecipieList::findRecipies(
+    ItemType* zTargetType, Framework::RCArray<Recipie>& recipies)
+{
+    for (Recipie* recipie : recipies)
+    {
+        if (recipie->createsOutput(zTargetType))
+        {
+            recipies.add(dynamic_cast<Recipie*>(recipie->getThis()));
+        }
+    }
+}

+ 8 - 29
FactoryCraft/RecipieList.h

@@ -3,38 +3,17 @@
 
 #include "Recipie.h"
 
-template<typename T, typename S> class RecipieListType
+class RecipieList
     : public virtual Framework::ReferenceCounter
 {
 private:
-    Framework::RCArray<T> recipies;
+    Framework::RCArray<Recipie> recipies;
     Framework::Text name;
 
 public:
-    RecipieListType(const char* name)
-        : ReferenceCounter(),
-          name(name)
-    {}
-
-    void addRecipie(T* recipie)
-    {
-        recipies.add(recipie);
-    }
-
-    T* zFirstRecipie(S* zStorage)
-    {
-        for (T* recipie : recipies)
-        {
-            if (recipie->testApplicability(zStorage)) return recipie;
-        }
-        return 0;
-    }
-
-    const Framework::Text& getName() const
-    {
-        return name;
-    }
-};
-
-typedef RecipieListType<Recipie, CraftingStorage> RecipieList;
-typedef RecipieListType<ShapedRecipie, ShapedCraftingStorage> ShapedRecipieList;
+    RecipieList(const char* name);
+    void addRecipie(Recipie* recipie);
+    Recipie* zFirstRecipie(CraftingStorage* zStorage);
+    const Framework::Text& getName() const;
+    void findRecipies(ItemType *zTargetType, Framework::RCArray<Recipie>& recipies);
+};

+ 48 - 18
FactoryCraft/RecipieLoader.cpp

@@ -93,14 +93,14 @@ void RecipieLoader::loadRecipie(JSONObject* zRecipie)
                 break;
             }
         }
-        recipie->setOutput(item, outputCount);
-        if (!zShapedRecipieList(group)) registerShapedRecipieList(group);
-        zShapedRecipieList(group)->addRecipie(recipie);
+        recipie->addOutput(item, outputCount);
+        if (!zRecipieList(group)) registerRecipieList(group);
+        zRecipieList(group)->addRecipie(recipie);
     }
     else if (zRecipie->zValue("type")->asString()->getString().istGleich(
                  "unordered"))
     {
-        Recipie* recipie = new Recipie();
+        UnshapedRecipie* recipie = new UnshapedRecipie();
         for (JSONValue* input : *zRecipie->zValue("inputs")->asArray())
         {
             int count = (int)input->asObject()
@@ -109,7 +109,13 @@ void RecipieLoader::loadRecipie(JSONObject* zRecipie)
                             ->getNumber();
             ItemFilter* filter
                 = loadFilter(input->asObject()->zValue("filter")->asObject());
-            recipie->addIngredient(filter, count);
+            CombinedItemModifier* resultingModifier
+                = new CombinedItemModifier();
+            for (JSONValue* modifier :
+                *input->asObject()->zValue("modifiers")->asArray())
+                resultingModifier->addModifier(
+                    loadModifier(modifier->asObject()));
+            recipie->addIngredient(filter, count, resultingModifier);
         }
         for (JSONValue* output : *zRecipie->zValue("outputs")->asArray())
         {
@@ -168,15 +174,6 @@ RecipieList* RecipieLoader::zRecipieList(const char* name) const
     return 0;
 }
 
-ShapedRecipieList* RecipieLoader::zShapedRecipieList(const char* name) const
-{
-    for (ShapedRecipieList* l : shapedLists)
-    {
-        if (l->getName().istGleich(name)) return l;
-    }
-    return 0;
-}
-
 void RecipieLoader::registerRecipieList(const char* name)
 {
     if (zRecipieList(name))
@@ -184,11 +181,27 @@ void RecipieLoader::registerRecipieList(const char* name)
     lists.add(new RecipieList(name));
 }
 
-void RecipieLoader::registerShapedRecipieList(const char* name)
+Framework::Text RecipieLoader::getCrafingUIML(ItemType* zTargetType)
 {
-    if (zShapedRecipieList(name))
-        throw new std::invalid_argument("the recipie list already exists");
-    shapedLists.add(new ShapedRecipieList(name));
+    Framework::Text result = "<craftingRecipies>";
+    for (RecipieList* list : lists)
+    {
+        Framework::RCArray<Recipie> recipies;
+        list->findRecipies(zTargetType, recipies);
+        if (recipies.getEintragAnzahl() > 0)
+        {
+            result += "<craftingRecipieGroup name=\"";
+            result += list->getName();
+            result += "\">";
+            for (Recipie* recipie : recipies)
+            {
+                result += recipie->getRecipieUIML();
+            }
+            result += "</craftingRecipieGroup>";
+        }
+    }
+    result += "</craftingRecipies>";
+    return result;
 }
 
 ItemModifier* RecipieLoader::loadModifier(
@@ -300,6 +313,23 @@ JSONValidator* RecipieLoader::zRecipieValidator()
                                       ->withRequiredAttribute("filter",
                                           dynamic_cast<JSONValidator*>(
                                               filterValidator->getThis()))
+                                      ->withRequiredAttribute("modifiers",
+                                          JSONValidator::buildForArray()
+                                              ->withDefault(Parser::getValue(
+                                                  "[{\"attribute\": \"hp\", "
+                                                  "\"value\": \"=0\"}]")
+                                                                ->asArray())
+                                              ->addAcceptedTypeInArray(
+                                                  JSONValidator::
+                                                      buildForObject()
+                                                          ->withRequiredString(
+                                                              "attribute")
+                                                          ->finishString()
+                                                          ->withRequiredString(
+                                                              "value")
+                                                          ->finishString()
+                                                          ->finishObject())
+                                              ->finishArray())
                                       ->finishObject())
                               ->finishArray())
                       ->withRequiredAttribute("output",

+ 1 - 3
FactoryCraft/RecipieLoader.h

@@ -7,7 +7,6 @@ class RecipieLoader : public virtual Framework::ReferenceCounter
 {
 private:
     Framework::RCArray<RecipieList> lists;
-    Framework::RCArray<ShapedRecipieList> shapedLists;
     Framework::JSON::Validator::JSONValidator* validator;
 
 public:
@@ -15,9 +14,8 @@ public:
     ~RecipieLoader();
     void loadRecipies(const char* path);
     RecipieList* zRecipieList(const char* name) const;
-    ShapedRecipieList* zShapedRecipieList(const char* name) const;
     void registerRecipieList(const char* name);
-    void registerShapedRecipieList(const char* name);
+    Framework::Text getCrafingUIML(ItemType* zTargetType);
 
 private:
     void loadRecipie(Framework::JSON::JSONObject* zRecipie);