From 38580fbee71d9833ae05eae604ce2301cd23218f Mon Sep 17 00:00:00 2001 From: darkrose Date: Thu, 12 Jul 2012 04:46:10 +1000 Subject: [PATCH] Add minetest.get_craft_recipe() --- doc/lua_api.txt | 7 ++++ src/craftdef.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++-- src/craftdef.h | 11 ++++++ src/scriptapi.cpp | 54 ++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 2 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 823b4b82..16f10815 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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) diff --git a/src/craftdef.cpp b/src/craftdef.cpp index ddb334fe..ab78e756 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -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 craftGetItemNames( return result; } +// convert a list of item names, to ItemStacks. +static std::vector craftGetItems( + const std::vector &items, IGameDef *gamedef) +{ + std::vector result; + for(std::vector::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 &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 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 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 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::const_reverse_iterator + i = m_craft_definitions.rbegin(); + i != m_craft_definitions.rend(); i++) + { + CraftDefinition *def = *i; + + /*infostream<<"Checking "<dump()<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 " + <dump()<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::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} };