1 /* 2 Minetest 3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as published by 7 the Free Software Foundation; either version 2.1 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #pragma once 21 22 #include <string> 23 #include <iostream> 24 #include <vector> 25 #include <utility> 26 #include "gamedef.h" 27 #include "inventory.h" 28 29 /* 30 Crafting methods. 31 32 The crafting method depends on the inventory list 33 that the crafting input comes from. 34 */ 35 enum CraftMethod 36 { 37 // Crafting grid 38 CRAFT_METHOD_NORMAL, 39 // Cooking something in a furnace 40 CRAFT_METHOD_COOKING, 41 // Using something as fuel for a furnace 42 CRAFT_METHOD_FUEL, 43 }; 44 45 /* 46 The type a hash can be. The earlier a type is mentioned in this enum, 47 the earlier it is tried at crafting, and the less likely is a collision. 48 Changing order causes changes in behaviour, so know what you do. 49 */ 50 enum CraftHashType 51 { 52 // Hashes the normalized names of the recipe's elements. 53 // Only recipes without group usage can be found here, 54 // because groups can't be guessed efficiently. 55 CRAFT_HASH_TYPE_ITEM_NAMES, 56 57 // Counts the non-empty slots. 58 CRAFT_HASH_TYPE_COUNT, 59 60 // This layer both spares an extra variable, and helps to retain (albeit rarely used) functionality. Maps to 0. 61 // Before hashes are "initialized", all hashes reside here, after initialisation, none are. 62 CRAFT_HASH_TYPE_UNHASHED 63 64 }; 65 const int craft_hash_type_max = (int) CRAFT_HASH_TYPE_UNHASHED; 66 67 /* 68 Input: The contents of the crafting slots, arranged in matrix form 69 */ 70 struct CraftInput 71 { 72 CraftMethod method = CRAFT_METHOD_NORMAL; 73 unsigned int width = 0; 74 std::vector<ItemStack> items; 75 76 CraftInput() = default; 77 CraftInputCraftInput78 CraftInput(CraftMethod method_, unsigned int width_, 79 const std::vector<ItemStack> &items_): 80 method(method_), width(width_), items(items_) 81 {} 82 83 // Returns true if all items are empty. 84 bool empty() const; 85 86 std::string dump() const; 87 }; 88 89 /* 90 Output: Result of crafting operation 91 */ 92 struct CraftOutput 93 { 94 // Used for normal crafting and cooking, itemstring 95 std::string item = ""; 96 // Used for cooking (cook time) and fuel (burn time), seconds 97 float time = 0.0f; 98 99 CraftOutput() = default; 100 CraftOutputCraftOutput101 CraftOutput(const std::string &item_, float time_): 102 item(item_), time(time_) 103 {} 104 std::string dump() const; 105 }; 106 107 /* 108 A list of replacements. A replacement indicates that a specific 109 input item should not be deleted (when crafting) but replaced with 110 a different item. Each replacements is a pair (itemstring to remove, 111 itemstring to replace with) 112 113 Example: If ("bucket:bucket_water", "bucket:bucket_empty") is a 114 replacement pair, the crafting input slot that contained a water 115 bucket will contain an empty bucket after crafting. 116 */ 117 struct CraftReplacements 118 { 119 // List of replacements 120 std::vector<std::pair<std::string, std::string> > pairs; 121 122 CraftReplacements() = default; CraftReplacementsCraftReplacements123 CraftReplacements(const std::vector<std::pair<std::string, std::string> > &pairs_): 124 pairs(pairs_) 125 {} 126 std::string dump() const; 127 }; 128 129 /* 130 Crafting definition base class 131 */ 132 class CraftDefinition 133 { 134 public: 135 /* 136 Craft recipe priorities, from low to high 137 138 Recipes are searched from latest to first. 139 If a recipe with higher priority than a previous found one is 140 encountered, it is selected instead. 141 */ 142 enum RecipePriority 143 { 144 PRIORITY_NO_RECIPE, 145 PRIORITY_TOOLREPAIR, 146 PRIORITY_SHAPELESS_AND_GROUPS, 147 PRIORITY_SHAPELESS, 148 PRIORITY_SHAPED_AND_GROUPS, 149 PRIORITY_SHAPED, 150 }; 151 152 CraftDefinition() = default; 153 virtual ~CraftDefinition() = default; 154 155 // Returns type of crafting definition 156 virtual std::string getName() const=0; 157 158 // Checks whether the recipe is applicable 159 virtual bool check(const CraftInput &input, IGameDef *gamedef) const=0; getPriority()160 RecipePriority getPriority() const 161 { 162 return priority; 163 } 164 // Returns the output structure, meaning depends on crafting method 165 // The implementation can assume that check(input) returns true 166 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const=0; 167 // the inverse of the above 168 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const=0; 169 // Decreases count of every input item 170 virtual void decrementInput(CraftInput &input, 171 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const=0; 172 getHashType()173 CraftHashType getHashType() const 174 { 175 return hash_type; 176 } 177 virtual u64 getHash(CraftHashType type) const = 0; 178 179 // to be called after all mods are loaded, so that we catch all aliases 180 virtual void initHash(IGameDef *gamedef) = 0; 181 182 virtual std::string dump() const=0; 183 184 protected: 185 CraftHashType hash_type; 186 RecipePriority priority; 187 }; 188 189 /* 190 A plain-jane (shaped) crafting definition 191 192 Supported crafting method: CRAFT_METHOD_NORMAL. 193 Requires the input items to be arranged exactly like in the recipe. 194 */ 195 class CraftDefinitionShaped: public CraftDefinition 196 { 197 public: 198 CraftDefinitionShaped() = delete; 199 CraftDefinitionShaped( 200 const std::string &output_, 201 unsigned int width_, 202 const std::vector<std::string> &recipe_, 203 const CraftReplacements &replacements_); 204 205 virtual ~CraftDefinitionShaped() = default; 206 207 virtual std::string getName() const; 208 virtual bool check(const CraftInput &input, IGameDef *gamedef) const; 209 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const; 210 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const; 211 virtual void decrementInput(CraftInput &input, 212 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const; 213 214 virtual u64 getHash(CraftHashType type) const; 215 216 virtual void initHash(IGameDef *gamedef); 217 218 virtual std::string dump() const; 219 220 private: 221 // Output itemstring 222 std::string output = ""; 223 // Width of recipe 224 unsigned int width = 1; 225 // Recipe matrix (itemstrings) 226 std::vector<std::string> recipe; 227 // Recipe matrix (item names) 228 std::vector<std::string> recipe_names; 229 // bool indicating if initHash has been called already 230 bool hash_inited = false; 231 // Replacement items for decrementInput() 232 CraftReplacements replacements; 233 }; 234 235 /* 236 A shapeless crafting definition 237 Supported crafting method: CRAFT_METHOD_NORMAL. 238 Input items can arranged in any way. 239 */ 240 class CraftDefinitionShapeless: public CraftDefinition 241 { 242 public: 243 CraftDefinitionShapeless() = delete; 244 CraftDefinitionShapeless( 245 const std::string &output_, 246 const std::vector<std::string> &recipe_, 247 const CraftReplacements &replacements_); 248 249 virtual ~CraftDefinitionShapeless() = default; 250 251 virtual std::string getName() const; 252 virtual bool check(const CraftInput &input, IGameDef *gamedef) const; 253 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const; 254 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const; 255 virtual void decrementInput(CraftInput &input, 256 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const; 257 258 virtual u64 getHash(CraftHashType type) const; 259 260 virtual void initHash(IGameDef *gamedef); 261 262 virtual std::string dump() const; 263 264 private: 265 // Output itemstring 266 std::string output; 267 // Recipe list (itemstrings) 268 std::vector<std::string> recipe; 269 // Recipe list (item names) 270 std::vector<std::string> recipe_names; 271 // bool indicating if initHash has been called already 272 bool hash_inited = false; 273 // Replacement items for decrementInput() 274 CraftReplacements replacements; 275 }; 276 277 /* 278 Tool repair crafting definition 279 Supported crafting method: CRAFT_METHOD_NORMAL. 280 Put two damaged tools into the crafting grid, get one tool back. 281 There should only be one crafting definition of this type. 282 */ 283 class CraftDefinitionToolRepair: public CraftDefinition 284 { 285 public: 286 CraftDefinitionToolRepair() = delete; 287 CraftDefinitionToolRepair(float additional_wear_); 288 289 virtual ~CraftDefinitionToolRepair() = default; 290 291 virtual std::string getName() const; 292 virtual bool check(const CraftInput &input, IGameDef *gamedef) const; 293 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const; 294 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const; 295 virtual void decrementInput(CraftInput &input, 296 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const; 297 getHash(CraftHashType type)298 virtual u64 getHash(CraftHashType type) const { return 2; } 299 initHash(IGameDef * gamedef)300 virtual void initHash(IGameDef *gamedef) 301 { 302 hash_type = CRAFT_HASH_TYPE_COUNT; 303 } 304 305 virtual std::string dump() const; 306 307 private: 308 // This is a constant that is added to the wear of the result. 309 // May be positive or negative, allowed range [-1,1]. 310 // 1 = new tool is completely broken 311 // 0 = simply add remaining uses of both input tools 312 // -1 = new tool is completely pristine 313 float additional_wear = 0.0f; 314 }; 315 316 /* 317 A cooking (in furnace) definition 318 Supported crafting method: CRAFT_METHOD_COOKING. 319 */ 320 class CraftDefinitionCooking: public CraftDefinition 321 { 322 public: 323 CraftDefinitionCooking() = delete; 324 CraftDefinitionCooking( 325 const std::string &output_, 326 const std::string &recipe_, 327 float cooktime_, 328 const CraftReplacements &replacements_); 329 330 virtual ~CraftDefinitionCooking() = default; 331 332 virtual std::string getName() const; 333 virtual bool check(const CraftInput &input, IGameDef *gamedef) const; 334 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const; 335 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const; 336 virtual void decrementInput(CraftInput &input, 337 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const; 338 339 virtual u64 getHash(CraftHashType type) const; 340 341 virtual void initHash(IGameDef *gamedef); 342 343 virtual std::string dump() const; 344 345 private: 346 // Output itemstring 347 std::string output; 348 // Recipe itemstring 349 std::string recipe; 350 // Recipe item name 351 std::string recipe_name; 352 // bool indicating if initHash has been called already 353 bool hash_inited = false; 354 // Time in seconds 355 float cooktime; 356 // Replacement items for decrementInput() 357 CraftReplacements replacements; 358 }; 359 360 /* 361 A fuel (for furnace) definition 362 Supported crafting method: CRAFT_METHOD_FUEL. 363 */ 364 class CraftDefinitionFuel: public CraftDefinition 365 { 366 public: 367 CraftDefinitionFuel() = delete; 368 CraftDefinitionFuel( 369 const std::string &recipe_, 370 float burntime_, 371 const CraftReplacements &replacements_); 372 373 virtual ~CraftDefinitionFuel() = default; 374 375 virtual std::string getName() const; 376 virtual bool check(const CraftInput &input, IGameDef *gamedef) const; 377 virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const; 378 virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const; 379 virtual void decrementInput(CraftInput &input, 380 std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const; 381 382 virtual u64 getHash(CraftHashType type) const; 383 384 virtual void initHash(IGameDef *gamedef); 385 386 virtual std::string dump() const; 387 388 private: 389 // Recipe itemstring 390 std::string recipe; 391 // Recipe item name 392 std::string recipe_name; 393 // bool indicating if initHash has been called already 394 bool hash_inited = false; 395 // Time in seconds 396 float burntime; 397 // Replacement items for decrementInput() 398 CraftReplacements replacements; 399 }; 400 401 /* 402 Crafting definition manager 403 */ 404 class ICraftDefManager 405 { 406 public: 407 ICraftDefManager() = default; 408 virtual ~ICraftDefManager() = default; 409 410 /** 411 * The main crafting function. 412 * 413 * @param input The input grid. 414 * @param output CraftOutput where the result is placed. 415 * @param output_replacements A vector of ItemStacks where replacements are 416 * placed if they cannot be placed in the input. Replacements can be placed 417 * in the input if the stack of the replaced item has a count of 1. 418 * @param decrementInput If true, consume or replace input items. 419 * @param gamedef 420 * @return true if a result was found, otherwise false. 421 */ 422 virtual bool getCraftResult(CraftInput &input, CraftOutput &output, 423 std::vector<ItemStack> &output_replacements, 424 bool decrementInput, IGameDef *gamedef) const=0; 425 426 virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output, 427 IGameDef *gamedef, unsigned limit=0) const=0; 428 429 // Print crafting recipes for debugging 430 virtual std::string dump() const=0; 431 }; 432 433 class IWritableCraftDefManager : public ICraftDefManager 434 { 435 public: 436 IWritableCraftDefManager() = default; 437 virtual ~IWritableCraftDefManager() = default; 438 439 // The main crafting function 440 virtual bool getCraftResult(CraftInput &input, CraftOutput &output, 441 std::vector<ItemStack> &output_replacements, 442 bool decrementInput, IGameDef *gamedef) const=0; 443 virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output, 444 IGameDef *gamedef, unsigned limit=0) const=0; 445 446 virtual bool clearCraftsByOutput(const CraftOutput &output, IGameDef *gamedef) = 0; 447 virtual bool clearCraftsByInput(const CraftInput &input, IGameDef *gamedef) = 0; 448 449 // Print crafting recipes for debugging 450 virtual std::string dump() const=0; 451 452 // Add a crafting definition. 453 // After calling this, the pointer belongs to the manager. 454 virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) = 0; 455 456 // Delete all crafting definitions 457 virtual void clear()=0; 458 459 // To be called after all mods are loaded, so that we catch all aliases 460 virtual void initHashes(IGameDef *gamedef) = 0; 461 }; 462 463 IWritableCraftDefManager* createCraftDefManager(); 464