Fix bone-attached entities (#10015)
[oweals/minetest.git] / src / craftdef.h
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
78         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
101         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;
123         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;
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
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
298         virtual u64 getHash(CraftHashType type) const { return 2; }
299
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();