Prioritise craft recipes
authorHybridDog <ovvv@web.de>
Wed, 3 Apr 2019 11:46:11 +0000 (13:46 +0200)
committerSmallJoker <mk939@ymail.com>
Mon, 20 May 2019 18:59:51 +0000 (20:59 +0200)
When multiple recipes are applicable, the recipes are prioritised in this order:
toolrepair < shapeless with groups < shapeless < shaped with groups < shaped
For cooking and fuel, items are prioritised over item groups

src/craftdef.cpp
src/craftdef.h

index 64e2f742b37b2f7612e83f01f296c7081aeade74..9482fce6a9a7f1953611828a1b1ed2a6dd00d987 100644 (file)
@@ -432,7 +432,13 @@ void CraftDefinitionShaped::initHash(IGameDef *gamedef)
                        break;
                }
        }
-       hash_type = has_group ? CRAFT_HASH_TYPE_COUNT : CRAFT_HASH_TYPE_ITEM_NAMES;
+       if (has_group) {
+               hash_type = CRAFT_HASH_TYPE_COUNT;
+               priority = SHAPED_AND_GROUPS;
+       } else {
+               hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
+               priority = SHAPED;
+       }
 }
 
 std::string CraftDefinitionShaped::dump() const
@@ -543,7 +549,13 @@ void CraftDefinitionShapeless::initHash(IGameDef *gamedef)
                        break;
                }
        }
-       hash_type = has_group ? CRAFT_HASH_TYPE_COUNT : CRAFT_HASH_TYPE_ITEM_NAMES;
+       if (has_group) {
+               hash_type = CRAFT_HASH_TYPE_COUNT;
+               priority = SHAPELESS_AND_GROUPS;
+       } else {
+               hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
+               priority = SHAPELESS;
+       }
 }
 
 std::string CraftDefinitionShapeless::dump() const
@@ -723,10 +735,13 @@ void CraftDefinitionCooking::initHash(IGameDef *gamedef)
        hash_inited = true;
        recipe_name = craftGetItemName(recipe, gamedef);
 
-       if (isGroupRecipeStr(recipe_name))
+       if (isGroupRecipeStr(recipe_name)) {
                hash_type = CRAFT_HASH_TYPE_COUNT;
-       else
+               priority = SHAPELESS_AND_GROUPS;
+       } else {
                hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
+               priority = SHAPELESS;
+       }
 }
 
 std::string CraftDefinitionCooking::dump() const
@@ -813,10 +828,13 @@ void CraftDefinitionFuel::initHash(IGameDef *gamedef)
        hash_inited = true;
        recipe_name = craftGetItemName(recipe, gamedef);
 
-       if (isGroupRecipeStr(recipe_name))
+       if (isGroupRecipeStr(recipe_name)) {
                hash_type = CRAFT_HASH_TYPE_COUNT;
-       else
+               priority = SHAPELESS_AND_GROUPS;
+       } else {
                hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
+               priority = SHAPELESS;
+       }
 }
 
 std::string CraftDefinitionFuel::dump() const
@@ -867,7 +885,11 @@ public:
                input_names = craftGetItemNames(input.items, gamedef);
                std::sort(input_names.begin(), input_names.end());
 
-               // Try hash types with increasing collision rate, and return if found.
+               // Try hash types with increasing collision rate
+               // while remembering the latest, highest priority recipe.
+               CraftDefinition::RecipePriority priority_best =
+                       CraftDefinition::NO_RECIPE;
+               CraftDefinition *def_best = nullptr;
                for (int type = 0; type <= craft_hash_type_max; type++) {
                        u64 hash = getHashForGrid((CraftHashType) type, input_names);
 
@@ -890,7 +912,9 @@ public:
                                /*errorstream << "Checking " << input.dump() << std::endl
                                        << " against " << def->dump() << std::endl;*/
 
-                               if (def->check(input, gamedef)) {
+                               CraftDefinition::RecipePriority priority = def->getPriority();
+                               if (priority > priority_best
+                                               && def->check(input, gamedef)) {
                                        // Check if the crafted node/item exists
                                        CraftOutput out = def->getOutput(input, gamedef);
                                        ItemStack is;
@@ -901,17 +925,17 @@ public:
                                                continue;
                                        }
 
-                                       // Get output, then decrement input (if requested)
                                        output = out;
-
-                                       if (decrementInput)
-                                               def->decrementInput(input, output_replacement, gamedef);
-                                       /*errorstream << "Check RETURNS TRUE" << std::endl;*/
-                                       return true;
+                                       priority_best = priority;
+                                       def_best = def;
                                }
                        }
                }
-               return false;
+               if (priority_best == CraftDefinition::NO_RECIPE)
+                       return false;
+               if (decrementInput)
+                       def_best->decrementInput(input, output_replacement, gamedef);
+               return true;
        }
 
        virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
index 140321f0f702495e7f1a328b3fbdb5b1040f3ba7..d8ad2eb22ae9df22e539fb96e28caa49a47276a9 100644 (file)
@@ -132,6 +132,23 @@ struct CraftReplacements
 class CraftDefinition
 {
 public:
+       /*
+               Craft recipe priorities, from low to high
+
+               Recipes are searched from latest to first.
+               If a recipe with higher priority than a previous found one is
+               encountered, it is selected instead.
+       */
+       enum RecipePriority
+       {
+               NO_RECIPE,
+               TOOLREPAIR,
+               SHAPELESS_AND_GROUPS,
+               SHAPELESS,
+               SHAPED_AND_GROUPS,
+               SHAPED,
+       };
+
        CraftDefinition() = default;
        virtual ~CraftDefinition() = default;
 
@@ -140,6 +157,10 @@ public:
 
        // Checks whether the recipe is applicable
        virtual bool check(const CraftInput &input, IGameDef *gamedef) const=0;
+       RecipePriority getPriority() const
+       {
+               return priority;
+       }
        // 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;
@@ -162,6 +183,7 @@ public:
 
 protected:
        CraftHashType hash_type;
+       RecipePriority priority;
 };
 
 /*
@@ -283,6 +305,7 @@ public:
        virtual void initHash(IGameDef *gamedef)
        {
                hash_type = CRAFT_HASH_TYPE_COUNT;
+               priority = TOOLREPAIR;
        }
 
        virtual std::string dump() const;