From 38580fbee71d9833ae05eae604ce2301cd23218f Mon Sep 17 00:00:00 2001
From: darkrose <lisa@ltmnet.com>
Date: Thu, 12 Jul 2012 04:46:10 +1000
Subject: Add minetest.get_craft_recipe()

---
 src/craftdef.cpp  | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/craftdef.h    | 11 +++++++
 src/scriptapi.cpp | 54 +++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+), 2 deletions(-)

(limited to 'src')

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}
 };
 
-- 
cgit v1.2.3