diff options
-rw-r--r-- | doc/lua_api.txt | 7 | ||||
-rw-r--r-- | src/craftdef.cpp | 90 | ||||
-rw-r--r-- | src/craftdef.h | 11 | ||||
-rw-r--r-- | src/scriptapi.cpp | 54 |
4 files changed, 160 insertions, 2 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 823b4b825..16f10815c 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 ddb334fe2..ab78e7560 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<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); diff --git a/src/craftdef.h b/src/craftdef.h index 107b4cf98..a2258c6e8 100644 --- a/src/craftdef.h +++ b/src/craftdef.h @@ -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; diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 25af2d105..4b3fbe296 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -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} }; |