+CraftOutput CraftDefinitionShapeless::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ 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);
+}
+
+CraftHashType CraftDefinitionShapeless::getHashType() const
+{
+ assert(hash_inited); // Pre-condition
+ bool has_group = false;
+ for (size_t i = 0; i < recipe_names.size(); i++) {
+ if (isGroupRecipeStr(recipe_names[i])) {
+ has_group = true;
+ break;
+ }
+ }
+ if (has_group)
+ return CRAFT_HASH_TYPE_COUNT;
+ else
+ return CRAFT_HASH_TYPE_ITEM_NAMES;
+}
+
+u64 CraftDefinitionShapeless::getHash(CraftHashType type) const
+{
+ assert(hash_inited); // Pre-condition
+ assert(type == CRAFT_HASH_TYPE_ITEM_NAMES
+ || type == CRAFT_HASH_TYPE_COUNT); // Pre-condition
+ return getHashForGrid(type, recipe_names);
+}
+
+void CraftDefinitionShapeless::initHash(IGameDef *gamedef)
+{
+ if (hash_inited)
+ return;
+ hash_inited = true;
+ recipe_names = craftGetItemNames(recipe, gamedef);
+ std::sort(recipe_names.begin(), recipe_names.end());
+}
+
+std::string CraftDefinitionShapeless::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os << "(shapeless, output=\"" << output
+ << "\", recipe=" << craftDumpMatrix(recipe, recipe.size())
+ << ", replacements=" << replacements.dump() << ")";
+ return os.str();
+}
+
+/*
+ CraftDefinitionToolRepair
+*/
+
+static ItemStack craftToolRepair(
+ const ItemStack &item1,
+ const ItemStack &item2,
+ float additional_wear,
+ IGameDef *gamedef)
+{
+ IItemDefManager *idef = gamedef->idef();
+ if (item1.count != 1 || item2.count != 1 || item1.name != item2.name
+ || idef->get(item1.name).type != ITEM_TOOL
+ || idef->get(item2.name).type != ITEM_TOOL) {
+ // Failure
+ return ItemStack();
+ }
+
+ s32 item1_uses = 65536 - (u32) item1.wear;
+ s32 item2_uses = 65536 - (u32) item2.wear;
+ s32 new_uses = item1_uses + item2_uses;
+ s32 new_wear = 65536 - new_uses + floor(additional_wear * 65536 + 0.5);
+ if (new_wear >= 65536)
+ return ItemStack();
+ if (new_wear < 0)
+ new_wear = 0;
+
+ ItemStack repaired = item1;
+ repaired.wear = new_wear;
+ return repaired;
+}
+
+std::string CraftDefinitionToolRepair::getName() const
+{
+ return "toolrepair";
+}
+
+bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if (input.method != CRAFT_METHOD_NORMAL)
+ return false;
+
+ ItemStack item1;
+ ItemStack item2;
+ for (std::vector<ItemStack>::const_iterator
+ it = input.items.begin();
+ it != input.items.end(); it++) {
+ if (!it->empty()) {
+ if (item1.empty())
+ item1 = *it;
+ else if (item2.empty())
+ item2 = *it;
+ else
+ return false;
+ }
+ }
+ ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
+ return !repaired.empty();
+}
+
+CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ ItemStack item1;
+ ItemStack item2;
+ for (std::vector<ItemStack>::const_iterator
+ it = input.items.begin();
+ it != input.items.end(); it++) {
+ if (!it->empty()) {
+ if (item1.empty())
+ item1 = *it;
+ else if (item2.empty())
+ item2 = *it;
+ }
+ }
+ ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef);
+ 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);
+}
+
+std::string CraftDefinitionToolRepair::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os << "(toolrepair, additional_wear=" << additional_wear << ")";
+ return os.str();
+}
+
+/*
+ CraftDefinitionCooking
+*/
+
+std::string CraftDefinitionCooking::getName() const
+{
+ return "cooking";
+}
+
+bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if (input.method != CRAFT_METHOD_COOKING)
+ return false;
+
+ // Filter empty items out of input
+ std::vector<std::string> input_filtered;
+ for (std::vector<ItemStack>::const_iterator
+ it = input.items.begin();
+ it != input.items.end(); it++) {
+ if (it->name != "")
+ input_filtered.push_back(it->name);
+ }
+
+ // If there is a wrong number of items in input, no match
+ if (input_filtered.size() != 1) {
+ /*dstream<<"Number of input items ("<<input_filtered.size()
+ <<") does not match recipe size (1) "
+ <<"of cooking recipe with output="<<output<<std::endl;*/
+ return false;
+ }
+
+ // Check the single input item
+ return inputItemMatchesRecipe(input_filtered[0], recipe, gamedef->idef());
+}
+
+CraftOutput CraftDefinitionCooking::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ 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);
+}
+
+CraftHashType CraftDefinitionCooking::getHashType() const
+{
+ if (isGroupRecipeStr(recipe_name))
+ return CRAFT_HASH_TYPE_COUNT;
+ else
+ return CRAFT_HASH_TYPE_ITEM_NAMES;
+}
+
+u64 CraftDefinitionCooking::getHash(CraftHashType type) const
+{
+ if (type == CRAFT_HASH_TYPE_ITEM_NAMES) {
+ return getHashForString(recipe_name);
+ } else if (type == CRAFT_HASH_TYPE_COUNT) {
+ return 1;
+ } else {
+ //illegal hash type for this CraftDefinition (pre-condition)
+ assert(false);
+ return 0;
+ }
+}
+
+void CraftDefinitionCooking::initHash(IGameDef *gamedef)
+{
+ if (hash_inited)
+ return;
+ hash_inited = true;
+ recipe_name = craftGetItemName(recipe, gamedef);
+}
+
+std::string CraftDefinitionCooking::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os << "(cooking, output=\"" << output
+ << "\", recipe=\"" << recipe
+ << "\", cooktime=" << cooktime << ")"
+ << ", replacements=" << replacements.dump() << ")";
+ return os.str();
+}
+
+/*
+ CraftDefinitionFuel
+*/
+
+std::string CraftDefinitionFuel::getName() const
+{
+ return "fuel";
+}
+
+bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) const
+{
+ if (input.method != CRAFT_METHOD_FUEL)
+ return false;
+
+ // Filter empty items out of input
+ std::vector<std::string> input_filtered;
+ for (std::vector<ItemStack>::const_iterator
+ it = input.items.begin();
+ it != input.items.end(); it++) {
+ if (it->name != "")
+ input_filtered.push_back(it->name);
+ }
+
+ // If there is a wrong number of items in input, no match
+ if (input_filtered.size() != 1) {
+ /*dstream<<"Number of input items ("<<input_filtered.size()
+ <<") does not match recipe size (1) "
+ <<"of fuel recipe with burntime="<<burntime<<std::endl;*/
+ return false;
+ }
+
+ // Check the single input item
+ return inputItemMatchesRecipe(input_filtered[0], recipe, gamedef->idef());
+}
+
+CraftOutput CraftDefinitionFuel::getOutput(const CraftInput &input, IGameDef *gamedef) const
+{
+ 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);
+}
+
+CraftHashType CraftDefinitionFuel::getHashType() const
+{
+ if (isGroupRecipeStr(recipe_name))
+ return CRAFT_HASH_TYPE_COUNT;
+ else
+ return CRAFT_HASH_TYPE_ITEM_NAMES;
+}
+
+u64 CraftDefinitionFuel::getHash(CraftHashType type) const
+{
+ if (type == CRAFT_HASH_TYPE_ITEM_NAMES) {
+ return getHashForString(recipe_name);
+ } else if (type == CRAFT_HASH_TYPE_COUNT) {
+ return 1;
+ } else {
+ //illegal hash type for this CraftDefinition (pre-condition)
+ assert(false);
+ return 0;
+ }
+}
+
+void CraftDefinitionFuel::initHash(IGameDef *gamedef)
+{
+ if (hash_inited)
+ return;
+ hash_inited = true;
+ recipe_name = craftGetItemName(recipe, gamedef);
+}
+std::string CraftDefinitionFuel::dump() const
+{
+ std::ostringstream os(std::ios::binary);
+ os << "(fuel, recipe=\"" << recipe
+ << "\", burntime=" << burntime << ")"
+ << ", replacements=" << replacements.dump() << ")";
+ return os.str();
+}
+
+/*
+ Craft definition manager
+*/
+