Add minetest.get_craft_recipe()
authordarkrose <lisa@ltmnet.com>
Wed, 11 Jul 2012 18:46:10 +0000 (04:46 +1000)
committerPerttu Ahola <celeron55@gmail.com>
Fri, 20 Jul 2012 23:33:22 +0000 (02:33 +0300)
doc/lua_api.txt
src/craftdef.cpp
src/craftdef.h
src/scriptapi.cpp

index 823b4b825eb3c60e8a01840ae9ccb7b74842e3a3..16f10815c7a45b684656bee6b8e85f5252b360e7 100644 (file)
@@ -829,6 +829,13 @@ minetest.get_craft_result(input) -> output, decremented_input
 ^ output.item = ItemStack, if unsuccessful: empty ItemStack
 ^ output.time = number, if unsuccessful: 0
 ^ decremented_input = like input
+minetest.get_craft_recipe(output) -> input
+^ output is a node or item type such as 'default:torch'
+^ input.method = 'normal' or 'cooking' or 'fuel'
+^ input.width = for example 3
+^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
+                              stack 5, stack 6, stack 7, stack 8, stack 9 }
+^ input.items = nil if no recipe found
 
 Defaults for the on_* item definition functions:
 (These return the leftover itemstack)
index ddb334fe29aa474e568c712f7a358da72eb5bb4f..ab78e7560d50b90cbfa591bed42043c20c154e3a 100644 (file)
@@ -35,7 +35,7 @@ static bool inputItemMatchesRecipe(const std::string &inp_name,
        // Exact name
        if(inp_name == rec_name)
                return true;
-       
+
        // Group
        if(rec_name.substr(0,6) == "group:" && idef->isKnown(inp_name)){
                std::string rec_group = rec_name.substr(6);
@@ -43,7 +43,7 @@ static bool inputItemMatchesRecipe(const std::string &inp_name,
                if(itemgroup_get(def.groups, rec_group) != 0)
                        return true;
        }
-       
+
        // Didn't match
        return false;
 }
@@ -84,6 +84,20 @@ static std::vector<std::string> craftGetItemNames(
        return result;
 }
 
+// convert a list of item names, to ItemStacks.
+static std::vector<ItemStack> craftGetItems(
+               const std::vector<std::string> &items, IGameDef *gamedef)
+{
+       std::vector<ItemStack> result;
+       for(std::vector<std::string>::const_iterator
+                       i = items.begin();
+                       i != items.end(); i++)
+       {
+               result.push_back(ItemStack(std::string(*i),(u16)1,(u16)0,"",gamedef->getItemDefManager()));
+       }
+       return result;
+}
+
 // Compute bounding rectangle given a matrix of items
 // Returns false if every item is ""
 static bool craftGetBounds(const std::vector<std::string> &items, unsigned int width,
@@ -439,6 +453,11 @@ CraftOutput CraftDefinitionShaped::getOutput(const CraftInput &input, IGameDef *
        return CraftOutput(output, 0);
 }
 
+CraftInput CraftDefinitionShaped::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+       return CraftInput(CRAFT_METHOD_NORMAL,width,craftGetItems(recipe,gamedef));
+}
+
 void CraftDefinitionShaped::decrementInput(CraftInput &input, IGameDef *gamedef) const
 {
        craftDecrementOrReplaceInput(input, replacements, gamedef);
@@ -507,6 +526,11 @@ CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDe
        return CraftOutput(output, 0);
 }
 
+CraftInput CraftDefinitionShapeless::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+       return CraftInput(CRAFT_METHOD_NORMAL,0,craftGetItems(recipe,gamedef));
+}
+
 void CraftDefinitionShapeless::decrementInput(CraftInput &input, IGameDef *gamedef) const
 {
        craftDecrementOrReplaceInput(input, replacements, gamedef);
@@ -625,6 +649,13 @@ CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameD
        return CraftOutput(repaired.getItemString(), 0);
 }
 
+CraftInput CraftDefinitionToolRepair::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+       std::vector<ItemStack> stack;
+       stack.push_back(ItemStack());
+       return CraftInput(CRAFT_METHOD_COOKING,additional_wear,stack);
+}
+
 void CraftDefinitionToolRepair::decrementInput(CraftInput &input, IGameDef *gamedef) const
 {
        craftDecrementInput(input, gamedef);
@@ -680,6 +711,13 @@ CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef
        return CraftOutput(output, cooktime);
 }
 
+CraftInput CraftDefinitionCooking::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+       std::vector<std::string> rec;
+       rec.push_back(recipe);
+       return CraftInput(CRAFT_METHOD_COOKING,cooktime,craftGetItems(rec,gamedef));
+}
+
 void CraftDefinitionCooking::decrementInput(CraftInput &input, IGameDef *gamedef) const
 {
        craftDecrementOrReplaceInput(input, replacements, gamedef);
@@ -744,6 +782,13 @@ CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *ga
        return CraftOutput("", burntime);
 }
 
+CraftInput CraftDefinitionFuel::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+       std::vector<std::string> rec;
+       rec.push_back(recipe);
+       return CraftInput(CRAFT_METHOD_COOKING,(int)burntime,craftGetItems(rec,gamedef));
+}
+
 void CraftDefinitionFuel::decrementInput(CraftInput &input, IGameDef *gamedef) const
 {
        craftDecrementOrReplaceInput(input, replacements, gamedef);
@@ -837,6 +882,47 @@ public:
                }
                return false;
        }
+       virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+                       IGameDef *gamedef) const
+       {
+               CraftOutput tmpout;
+               tmpout.item = "";
+               tmpout.time = 0;
+
+               // If output item is empty, abort.
+               if(output.item.empty())
+                       return false;
+
+               // Walk crafting definitions from back to front, so that later
+               // definitions can override earlier ones.
+               for(std::vector<CraftDefinition*>::const_reverse_iterator
+                               i = m_craft_definitions.rbegin();
+                               i != m_craft_definitions.rend(); i++)
+               {
+                       CraftDefinition *def = *i;
+
+                       /*infostream<<"Checking "<<input.dump()<<std::endl
+                                       <<" against "<<def->dump()<<std::endl;*/
+
+                       try {
+                               tmpout = def->getOutput(input, gamedef);
+                               if(tmpout.item.substr(0,output.item.length()) == output.item)
+                               {
+                                       // Get output, then decrement input (if requested)
+                                       input = def->getInput(output, gamedef);
+                                       return true;
+                               }
+                       }
+                       catch(SerializationError &e)
+                       {
+                               errorstream<<"getCraftResult: ERROR: "
+                                               <<"Serialization error in recipe "
+                                               <<def->dump()<<std::endl;
+                               // then go on with the next craft definition
+                       }
+               }
+               return false;
+       }
        virtual std::string dump() const
        {
                std::ostringstream os(std::ios::binary);
index 107b4cf987f9a3f91af825ef02e044ea5a7517cf..a2258c6e84b9a65d9ef7e6b8516043bc6e72eab0 100644 (file)
@@ -130,6 +130,8 @@ public:
        // Returns the output structure, meaning depends on crafting method
        // The implementation can assume that check(input) returns true
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const=0;
+       // the inverse of the above
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const=0;
        // Decreases count of every input item
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const=0;
 
@@ -164,6 +166,7 @@ public:
        virtual std::string getName() const;
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
 
        virtual std::string dump() const;
@@ -205,6 +208,7 @@ public:
        virtual std::string getName() const;
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
 
        virtual std::string dump() const;
@@ -242,6 +246,7 @@ public:
        virtual std::string getName() const;
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
 
        virtual std::string dump() const;
@@ -281,6 +286,7 @@ public:
        virtual std::string getName() const;
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
 
        virtual std::string dump() const;
@@ -320,6 +326,7 @@ public:
        virtual std::string getName() const;
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
        virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+       virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
        virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
 
        virtual std::string dump() const;
@@ -349,6 +356,8 @@ public:
        // The main crafting function
        virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
                        bool decrementInput, IGameDef *gamedef) const=0;
+       virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+                       IGameDef *gamedef) const=0;
        
        // Print crafting recipes for debugging
        virtual std::string dump() const=0;
@@ -365,6 +374,8 @@ public:
        // The main crafting function
        virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
                        bool decrementInput, IGameDef *gamedef) const=0;
+       virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+                       IGameDef *gamedef) const=0;
 
        // Print crafting recipes for debugging
        virtual std::string dump() const=0;
index 25af2d105b347b21f3bca9fc2fe754b71ac6ee94..4b3fbe2968822a6360f60c9b4a1191897dc831c2 100644 (file)
@@ -4558,6 +4558,59 @@ static int l_get_craft_result(lua_State *L)
        return 2;
 }
 
+// get_craft_recipe(result item)
+static int l_get_craft_recipe(lua_State *L)
+{
+       int k = 0;
+       char tmp[20];
+       int input_i = 1;
+       std::string o_item = luaL_checkstring(L,input_i);
+       
+       IGameDef *gdef = get_server(L);
+       ICraftDefManager *cdef = gdef->cdef();
+       CraftInput input;
+       CraftOutput output(o_item,0);
+       bool got = cdef->getCraftRecipe(input, output, gdef);
+       lua_newtable(L); // output table
+       if(got){
+               lua_newtable(L);
+               for(std::vector<ItemStack>::const_iterator
+                       i = input.items.begin();
+                       i != input.items.end(); i++, k++)
+               {
+                       if (i->empty())
+                       {
+                               continue;
+                       }
+                       sprintf(tmp,"%d",k);
+                       lua_pushstring(L,tmp);
+                       lua_pushstring(L,i->name.c_str());
+                       lua_settable(L, -3);
+               }
+               lua_setfield(L, -2, "items");
+               setintfield(L, -1, "width", input.width);
+               switch (input.method) {
+               case CRAFT_METHOD_NORMAL:
+                       lua_pushstring(L,"noraml");
+                       break;
+               case CRAFT_METHOD_COOKING:
+                       lua_pushstring(L,"cooking");
+                       break;
+               case CRAFT_METHOD_FUEL:
+                       lua_pushstring(L,"fuel");
+                       break;
+               default:
+                       lua_pushstring(L,"unknown");
+               }
+               lua_setfield(L, -2, "type");
+       } else {
+               lua_pushnil(L);
+               lua_setfield(L, -2, "items");
+               setintfield(L, -1, "width", 0);
+       }
+       return 1;
+}
+
 static const struct luaL_Reg minetest_f [] = {
        {"debug", l_debug},
        {"log", l_log},
@@ -4582,6 +4635,7 @@ static const struct luaL_Reg minetest_f [] = {
        {"get_password_hash", l_get_password_hash},
        {"notify_authentication_modified", l_notify_authentication_modified},
        {"get_craft_result", l_get_craft_result},
+       {"get_craft_recipe", l_get_craft_recipe},
        {NULL, NULL}
 };