mirror of
https://github.com/minetest/minetest.git
synced 2024-12-23 22:52:25 +01:00
Working group-shapeless and multigroup recipes
This commit is contained in:
parent
a26a66a8c4
commit
0c91a0d59d
@ -423,7 +423,7 @@ effective towards.
|
|||||||
|
|
||||||
Groups in crafting recipes
|
Groups in crafting recipes
|
||||||
---------------------------
|
---------------------------
|
||||||
An example:
|
An example: Make meat soup from any meat, any water and any bowl
|
||||||
{
|
{
|
||||||
output = 'food:meat_soup_raw',
|
output = 'food:meat_soup_raw',
|
||||||
recipe = {
|
recipe = {
|
||||||
@ -431,7 +431,13 @@ An example:
|
|||||||
{'group:water'},
|
{'group:water'},
|
||||||
{'group:bowl'},
|
{'group:bowl'},
|
||||||
},
|
},
|
||||||
preserve = {'group:bowl'}, -- Not implemented yet (TODO)
|
-- preserve = {'group:bowl'}, -- Not implemented yet (TODO)
|
||||||
|
}
|
||||||
|
An another example: Make red wool from white wool and red dye
|
||||||
|
{
|
||||||
|
type = 'shapeless',
|
||||||
|
output = 'wool:red',
|
||||||
|
recipe = {'wool:white', 'group:dye,basecolor_red'},
|
||||||
}
|
}
|
||||||
|
|
||||||
Special groups
|
Special groups
|
||||||
|
120
src/craftdef.cpp
120
src/craftdef.cpp
@ -23,9 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
|
#include "strfnd.h"
|
||||||
|
|
||||||
// Check if input matches recipe
|
// Check if input matches recipe
|
||||||
// Takes recipe groups into account
|
// Takes recipe groups into account
|
||||||
@ -38,9 +40,17 @@ static bool inputItemMatchesRecipe(const std::string &inp_name,
|
|||||||
|
|
||||||
// Group
|
// Group
|
||||||
if(rec_name.substr(0,6) == "group:" && idef->isKnown(inp_name)){
|
if(rec_name.substr(0,6) == "group:" && idef->isKnown(inp_name)){
|
||||||
std::string rec_group = rec_name.substr(6);
|
|
||||||
const struct ItemDefinition &def = idef->get(inp_name);
|
const struct ItemDefinition &def = idef->get(inp_name);
|
||||||
if(itemgroup_get(def.groups, rec_group) != 0)
|
Strfnd f(rec_name.substr(6));
|
||||||
|
bool all_groups_match = true;
|
||||||
|
do{
|
||||||
|
std::string check_group = f.next(",");
|
||||||
|
if(itemgroup_get(def.groups, check_group) == 0){
|
||||||
|
all_groups_match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(!f.atend());
|
||||||
|
if(all_groups_match)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +150,8 @@ static bool craftGetBounds(const std::vector<std::string> &items, unsigned int w
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// This became useless when group support was added to shapeless recipes
|
||||||
// Convert a list of item names to a multiset
|
// Convert a list of item names to a multiset
|
||||||
static std::multiset<std::string> craftMakeMultiset(const std::vector<std::string> &names)
|
static std::multiset<std::string> craftMakeMultiset(const std::vector<std::string> &names)
|
||||||
{
|
{
|
||||||
@ -153,6 +165,7 @@ static std::multiset<std::string> craftMakeMultiset(const std::vector<std::strin
|
|||||||
}
|
}
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Removes 1 from each item stack
|
// Removes 1 from each item stack
|
||||||
static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
|
static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
|
||||||
@ -508,17 +521,48 @@ bool CraftDefinitionShapeless::check(const CraftInput &input, IGameDef *gamedef)
|
|||||||
{
|
{
|
||||||
if(input.method != CRAFT_METHOD_NORMAL)
|
if(input.method != CRAFT_METHOD_NORMAL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Filter empty items out of input
|
||||||
|
std::vector<std::string> input_filtered;
|
||||||
|
for(std::vector<ItemStack>::const_iterator
|
||||||
|
i = input.items.begin();
|
||||||
|
i != input.items.end(); i++)
|
||||||
|
{
|
||||||
|
if(i->name != "")
|
||||||
|
input_filtered.push_back(i->name);
|
||||||
|
}
|
||||||
|
|
||||||
// Get input item multiset
|
// If there is a wrong number of items in input, no match
|
||||||
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
|
if(input_filtered.size() != recipe.size()){
|
||||||
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
|
/*dstream<<"Number of input items ("<<input_filtered.size()
|
||||||
|
<<") does not match recipe size ("<<recipe.size()<<") "
|
||||||
|
<<"of recipe with output="<<output<<std::endl;*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Get recipe item multiset
|
// Try with all permutations of the recipe
|
||||||
std::vector<std::string> rec_names = craftGetItemNames(recipe, gamedef);
|
std::vector<std::string> recipe_copy = recipe;
|
||||||
std::multiset<std::string> rec_names_multiset = craftMakeMultiset(rec_names);
|
// Start from the lexicographically first permutation (=sorted)
|
||||||
|
std::sort(recipe_copy.begin(), recipe_copy.end());
|
||||||
|
//while(std::prev_permutation(recipe_copy.begin(), recipe_copy.end())){}
|
||||||
|
do{
|
||||||
|
// If all items match, the recipe matches
|
||||||
|
bool all_match = true;
|
||||||
|
//dstream<<"Testing recipe (output="<<output<<"):";
|
||||||
|
for(size_t i=0; i<recipe.size(); i++){
|
||||||
|
//dstream<<" ("<<input_filtered[i]<<" == "<<recipe_copy[i]<<")";
|
||||||
|
if(!inputItemMatchesRecipe(input_filtered[i], recipe_copy[i],
|
||||||
|
gamedef->idef())){
|
||||||
|
all_match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//dstream<<" -> match="<<all_match<<std::endl;
|
||||||
|
if(all_match)
|
||||||
|
return true;
|
||||||
|
}while(std::next_permutation(recipe_copy.begin(), recipe_copy.end()));
|
||||||
|
|
||||||
// Recipe is matched when the multisets coincide
|
return false;
|
||||||
return inp_names_multiset == rec_names_multiset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
||||||
@ -694,16 +738,26 @@ bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) c
|
|||||||
if(input.method != CRAFT_METHOD_COOKING)
|
if(input.method != CRAFT_METHOD_COOKING)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get input item multiset
|
// Filter empty items out of input
|
||||||
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
|
std::vector<std::string> input_filtered;
|
||||||
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
|
for(std::vector<ItemStack>::const_iterator
|
||||||
|
i = input.items.begin();
|
||||||
|
i != input.items.end(); i++)
|
||||||
|
{
|
||||||
|
if(i->name != "")
|
||||||
|
input_filtered.push_back(i->name);
|
||||||
|
}
|
||||||
|
|
||||||
// Get recipe item multiset
|
// If there is a wrong number of items in input, no match
|
||||||
std::multiset<std::string> rec_names_multiset;
|
if(input_filtered.size() != 1){
|
||||||
rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
|
/*dstream<<"Number of input items ("<<input_filtered.size()
|
||||||
|
<<") does not match recipe size (1) "
|
||||||
// Recipe is matched when the multisets coincide
|
<<"of cooking recipe with output="<<output<<std::endl;*/
|
||||||
return inp_names_multiset == rec_names_multiset;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the single input item
|
||||||
|
return inputItemMatchesRecipe(input_filtered[0], recipe, gamedef->idef());
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
||||||
@ -765,16 +819,26 @@ bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) cons
|
|||||||
if(input.method != CRAFT_METHOD_FUEL)
|
if(input.method != CRAFT_METHOD_FUEL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get input item multiset
|
// Filter empty items out of input
|
||||||
std::vector<std::string> inp_names = craftGetItemNames(input.items, gamedef);
|
std::vector<std::string> input_filtered;
|
||||||
std::multiset<std::string> inp_names_multiset = craftMakeMultiset(inp_names);
|
for(std::vector<ItemStack>::const_iterator
|
||||||
|
i = input.items.begin();
|
||||||
|
i != input.items.end(); i++)
|
||||||
|
{
|
||||||
|
if(i->name != "")
|
||||||
|
input_filtered.push_back(i->name);
|
||||||
|
}
|
||||||
|
|
||||||
// Get recipe item multiset
|
// If there is a wrong number of items in input, no match
|
||||||
std::multiset<std::string> rec_names_multiset;
|
if(input_filtered.size() != 1){
|
||||||
rec_names_multiset.insert(craftGetItemName(recipe, gamedef));
|
/*dstream<<"Number of input items ("<<input_filtered.size()
|
||||||
|
<<") does not match recipe size (1) "
|
||||||
// Recipe is matched when the multisets coincide
|
<<"of fuel recipe with burntime="<<burntime<<std::endl;*/
|
||||||
return inp_names_multiset == rec_names_multiset;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the single input item
|
||||||
|
return inputItemMatchesRecipe(input_filtered[0], recipe, gamedef->idef());
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *gamedef) const
|
||||||
|
Loading…
Reference in New Issue
Block a user