/*
-Minetest-c55
-Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GNU Lesser General Public License for more details.
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef CRAFTDEF_HEADER
-#define CRAFTDEF_HEADER
+#pragma once
#include <string>
#include <iostream>
#include <vector>
-class IGameDef;
-class InventoryItem;
+#include <utility>
+#include "gamedef.h"
+#include "inventory.h"
-struct CraftPointerInput
+/*
+ Crafting methods.
+
+ The crafting method depends on the inventory list
+ that the crafting input comes from.
+*/
+enum CraftMethod
{
- unsigned int width;
- std::vector<InventoryItem*> items;
+ // Crafting grid
+ CRAFT_METHOD_NORMAL,
+ // Cooking something in a furnace
+ CRAFT_METHOD_COOKING,
+ // Using something as fuel for a furnace
+ CRAFT_METHOD_FUEL,
+};
+
+/*
+ The type a hash can be. The earlier a type is mentioned in this enum,
+ the earlier it is tried at crafting, and the less likely is a collision.
+ Changing order causes changes in behaviour, so know what you do.
+ */
+enum CraftHashType
+{
+ // Hashes the normalized names of the recipe's elements.
+ // Only recipes without group usage can be found here,
+ // because groups can't be guessed efficiently.
+ CRAFT_HASH_TYPE_ITEM_NAMES,
+
+ // Counts the non-empty slots.
+ CRAFT_HASH_TYPE_COUNT,
+
+ // This layer both spares an extra variable, and helps to retain (albeit rarely used) functionality. Maps to 0.
+ // Before hashes are "initialized", all hashes reside here, after initialisation, none are.
+ CRAFT_HASH_TYPE_UNHASHED
- CraftPointerInput(unsigned int width_, const std::vector<InventoryItem*> &items_):
- width(width_),
- items(items_)
- {}
- CraftPointerInput():
- width(0)
- {}
- ~CraftPointerInput();
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
};
+const int craft_hash_type_max = (int) CRAFT_HASH_TYPE_UNHASHED;
+/*
+ Input: The contents of the crafting slots, arranged in matrix form
+*/
struct CraftInput
{
- unsigned int width;
- std::vector<std::string> items;
+ CraftMethod method = CRAFT_METHOD_NORMAL;
+ unsigned int width = 0;
+ std::vector<ItemStack> items;
- CraftInput(unsigned int width_, const std::vector<std::string> &items_):
- width(width_),
- items(items_)
+ CraftInput() = default;
+
+ CraftInput(CraftMethod method_, unsigned int width_,
+ const std::vector<ItemStack> &items_):
+ method(method_), width(width_), items(items_)
{}
- CraftInput():
- width(0)
+
+ // Returns true if all items are empty.
+ bool empty() const;
+
+ std::string dump() const;
+};
+
+/*
+ Output: Result of crafting operation
+*/
+struct CraftOutput
+{
+ // Used for normal crafting and cooking, itemstring
+ std::string item = "";
+ // Used for cooking (cook time) and fuel (burn time), seconds
+ float time = 0.0f;
+
+ CraftOutput() = default;
+
+ CraftOutput(const std::string &item_, float time_):
+ item(item_), time(time_)
{}
- unsigned int height() const{
- return (items.size() + width - 1) / width;
- }
std::string dump() const;
};
-struct CraftDefinition
+/*
+ A list of replacements. A replacement indicates that a specific
+ input item should not be deleted (when crafting) but replaced with
+ a different item. Each replacements is a pair (itemstring to remove,
+ itemstring to replace with)
+
+ Example: If ("bucket:bucket_water", "bucket:bucket_empty") is a
+ replacement pair, the crafting input slot that contained a water
+ bucket will contain an empty bucket after crafting.
+*/
+struct CraftReplacements
{
- std::string output;
- CraftInput input;
+ // List of replacements
+ std::vector<std::pair<std::string, std::string> > pairs;
- CraftDefinition(){}
- CraftDefinition(const std::string &output_, unsigned int width_,
- const std::vector<std::string> &input_):
- output(output_),
- input(width_, input_)
+ CraftReplacements() = default;
+ CraftReplacements(const std::vector<std::pair<std::string, std::string> > &pairs_):
+ pairs(pairs_)
{}
-
std::string dump() const;
- void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is);
};
+/*
+ Crafting definition base class
+*/
+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
+ {
+ PRIORITY_NO_RECIPE,
+ PRIORITY_TOOLREPAIR,
+ PRIORITY_SHAPELESS_AND_GROUPS,
+ PRIORITY_SHAPELESS,
+ PRIORITY_SHAPED_AND_GROUPS,
+ PRIORITY_SHAPED,
+ };
+
+ CraftDefinition() = default;
+ virtual ~CraftDefinition() = default;
+
+ // Returns type of crafting definition
+ virtual std::string getName() const=0;
+
+ // 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;
+ // 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const=0;
+
+ CraftHashType getHashType() const
+ {
+ return hash_type;
+ }
+ virtual u64 getHash(CraftHashType type) const = 0;
+
+ // to be called after all mods are loaded, so that we catch all aliases
+ virtual void initHash(IGameDef *gamedef) = 0;
+
+ virtual std::string dump() const=0;
+
+protected:
+ CraftHashType hash_type;
+ RecipePriority priority;
+};
+
+/*
+ A plain-jane (shaped) crafting definition
+
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Requires the input items to be arranged exactly like in the recipe.
+*/
+class CraftDefinitionShaped: public CraftDefinition
+{
+public:
+ CraftDefinitionShaped() = delete;
+ CraftDefinitionShaped(
+ const std::string &output_,
+ unsigned int width_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_);
+
+ virtual ~CraftDefinitionShaped() = default;
+
+ 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
+
+ virtual u64 getHash(CraftHashType type) const;
+
+ virtual void initHash(IGameDef *gamedef);
+
+ virtual std::string dump() const;
+
+private:
+ // Output itemstring
+ std::string output = "";
+ // Width of recipe
+ unsigned int width = 1;
+ // Recipe matrix (itemstrings)
+ std::vector<std::string> recipe;
+ // Recipe matrix (item names)
+ std::vector<std::string> recipe_names;
+ // bool indicating if initHash has been called already
+ bool hash_inited = false;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ A shapeless crafting definition
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Input items can arranged in any way.
+*/
+class CraftDefinitionShapeless: public CraftDefinition
+{
+public:
+ CraftDefinitionShapeless() = delete;
+ CraftDefinitionShapeless(
+ const std::string &output_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_);
+
+ virtual ~CraftDefinitionShapeless() = default;
+
+ 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
+
+ virtual u64 getHash(CraftHashType type) const;
+
+ virtual void initHash(IGameDef *gamedef);
+
+ virtual std::string dump() const;
+
+private:
+ // Output itemstring
+ std::string output;
+ // Recipe list (itemstrings)
+ std::vector<std::string> recipe;
+ // Recipe list (item names)
+ std::vector<std::string> recipe_names;
+ // bool indicating if initHash has been called already
+ bool hash_inited = false;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ Tool repair crafting definition
+ Supported crafting method: CRAFT_METHOD_NORMAL.
+ Put two damaged tools into the crafting grid, get one tool back.
+ There should only be one crafting definition of this type.
+*/
+class CraftDefinitionToolRepair: public CraftDefinition
+{
+public:
+ CraftDefinitionToolRepair() = delete;
+ CraftDefinitionToolRepair(float additional_wear_);
+
+ virtual ~CraftDefinitionToolRepair() = default;
+
+ 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
+
+ virtual u64 getHash(CraftHashType type) const { return 2; }
+
+ virtual void initHash(IGameDef *gamedef)
+ {
+ hash_type = CRAFT_HASH_TYPE_COUNT;
+ }
+
+ virtual std::string dump() const;
+
+private:
+ // This is a constant that is added to the wear of the result.
+ // May be positive or negative, allowed range [-1,1].
+ // 1 = new tool is completely broken
+ // 0 = simply add remaining uses of both input tools
+ // -1 = new tool is completely pristine
+ float additional_wear = 0.0f;
+};
+
+/*
+ A cooking (in furnace) definition
+ Supported crafting method: CRAFT_METHOD_COOKING.
+*/
+class CraftDefinitionCooking: public CraftDefinition
+{
+public:
+ CraftDefinitionCooking() = delete;
+ CraftDefinitionCooking(
+ const std::string &output_,
+ const std::string &recipe_,
+ float cooktime_,
+ const CraftReplacements &replacements_);
+
+ virtual ~CraftDefinitionCooking() = default;
+
+ 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
+
+ virtual u64 getHash(CraftHashType type) const;
+
+ virtual void initHash(IGameDef *gamedef);
+
+ virtual std::string dump() const;
+
+private:
+ // Output itemstring
+ std::string output;
+ // Recipe itemstring
+ std::string recipe;
+ // Recipe item name
+ std::string recipe_name;
+ // bool indicating if initHash has been called already
+ bool hash_inited = false;
+ // Time in seconds
+ float cooktime;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ A fuel (for furnace) definition
+ Supported crafting method: CRAFT_METHOD_FUEL.
+*/
+class CraftDefinitionFuel: public CraftDefinition
+{
+public:
+ CraftDefinitionFuel() = delete;
+ CraftDefinitionFuel(
+ const std::string &recipe_,
+ float burntime_,
+ const CraftReplacements &replacements_);
+
+ virtual ~CraftDefinitionFuel() = default;
+
+ 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,
+ std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
+
+ virtual u64 getHash(CraftHashType type) const;
+
+ virtual void initHash(IGameDef *gamedef);
+
+ virtual std::string dump() const;
+
+private:
+ // Recipe itemstring
+ std::string recipe;
+ // Recipe item name
+ std::string recipe_name;
+ // bool indicating if initHash has been called already
+ bool hash_inited = false;
+ // Time in seconds
+ float burntime;
+ // Replacement items for decrementInput()
+ CraftReplacements replacements;
+};
+
+/*
+ Crafting definition manager
+*/
class ICraftDefManager
{
public:
- ICraftDefManager(){}
- virtual ~ICraftDefManager(){}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const=0;
-
- virtual void serialize(std::ostream &os)=0;
+ ICraftDefManager() = default;
+ virtual ~ICraftDefManager() = default;
+
+ /**
+ * The main crafting function.
+ *
+ * @param input The input grid.
+ * @param output CraftOutput where the result is placed.
+ * @param output_replacements A vector of ItemStacks where replacements are
+ * placed if they cannot be placed in the input. Replacements can be placed
+ * in the input if the stack of the replaced item has a count of 1.
+ * @param decrementInput If true, consume or replace input items.
+ * @param gamedef
+ * @return true if a result was found, otherwise false.
+ */
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ std::vector<ItemStack> &output_replacements,
+ bool decrementInput, IGameDef *gamedef) const=0;
+
+ virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
+ IGameDef *gamedef, unsigned limit=0) const=0;
+
+ // Print crafting recipes for debugging
+ virtual std::string dump() const=0;
};
class IWritableCraftDefManager : public ICraftDefManager
{
public:
- IWritableCraftDefManager(){}
- virtual ~IWritableCraftDefManager(){}
- virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
- IGameDef *gamedef) const=0;
-
- virtual void registerCraft(const CraftDefinition &def)=0;
+ IWritableCraftDefManager() = default;
+ virtual ~IWritableCraftDefManager() = default;
+
+ // The main crafting function
+ virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
+ std::vector<ItemStack> &output_replacements,
+ bool decrementInput, IGameDef *gamedef) const=0;
+ virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
+ IGameDef *gamedef, unsigned limit=0) const=0;
+
+ virtual bool clearCraftsByOutput(const CraftOutput &output, IGameDef *gamedef) = 0;
+ virtual bool clearCraftsByInput(const CraftInput &input, IGameDef *gamedef) = 0;
+
+ // Print crafting recipes for debugging
+ virtual std::string dump() const=0;
+
+ // Add a crafting definition.
+ // After calling this, the pointer belongs to the manager.
+ virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) = 0;
+
+ // Delete all crafting definitions
virtual void clear()=0;
- virtual void serialize(std::ostream &os)=0;
- virtual void deSerialize(std::istream &is)=0;
+ // To be called after all mods are loaded, so that we catch all aliases
+ virtual void initHashes(IGameDef *gamedef) = 0;
};
IWritableCraftDefManager* createCraftDefManager();
-
-#endif
-