+ clay and associated items
[oweals/minetest.git] / src / mapnode.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 #ifndef MAPNODE_HEADER
21 #define MAPNODE_HEADER
22
23 #include <iostream>
24 #include "common_irrlicht.h"
25 #include "light.h"
26 #include "utility.h"
27 #include "exceptions.h"
28 #include "serialization.h"
29 #include "tile.h"
30
31 /*
32         Initializes all kind of stuff in here.
33         Many things depend on this.
34
35         This accesses g_texturesource; if it is non-NULL, textures are set.
36
37         Client first calls this with g_texturesource=NULL to run some
38         unit tests and stuff, then it runs this again with g_texturesource
39         defined to get the textures.
40
41         Server only calls this once with g_texturesource=NULL.
42 */
43 void init_mapnode();
44
45 // Initializes g_content_inventory_texture_paths
46 void init_content_inventory_texture_paths();
47
48
49 // NOTE: This is not used appropriately everywhere.
50 #define MATERIALS_COUNT 256
51
52 /*
53         Ignored node.
54
55         Anything that stores MapNodes doesn't have to preserve parameters
56         associated with this material.
57         
58         Doesn't create faces with anything and is considered being
59         out-of-map in the game map.
60 */
61 #define CONTENT_IGNORE 255
62 #define CONTENT_IGNORE_DEFAULT_PARAM 0
63
64 /*
65         The common material through which the player can walk and which
66         is transparent to light
67 */
68 #define CONTENT_AIR 254
69
70 /*
71         Suggested materials:
72         - Gravel
73         - Sand
74         
75         New naming scheme:
76         - Material = irrlicht's Material class
77         - Content = (u8) content of a node
78         - Tile = (u16) Material ID at some side of a node
79 */
80
81 #define CONTENT_STONE 0
82 #define CONTENT_GRASS 1
83 #define CONTENT_WATER 2
84 #define CONTENT_TORCH 3
85 #define CONTENT_TREE 4
86 #define CONTENT_LEAVES 5
87 #define CONTENT_GRASS_FOOTSTEPS 6
88 #define CONTENT_MESE 7
89 #define CONTENT_MUD 8
90 #define CONTENT_WATERSOURCE 9
91 // Pretty much useless, clouds won't be drawn this way
92 #define CONTENT_CLOUD 10
93 #define CONTENT_COALSTONE 11
94 #define CONTENT_WOOD 12
95 #define CONTENT_SAND 13
96 #define CONTENT_SIGN_WALL 14
97 #define CONTENT_CHEST 15
98 #define CONTENT_FURNACE 16
99 //#define CONTENT_WORKBENCH 17
100 #define CONTENT_COBBLE 18
101 #define CONTENT_STEEL 19
102 #define CONTENT_GLASS 20
103 #define CONTENT_FENCE 21
104 #define CONTENT_SANDSTONE 22
105 #define CONTENT_CACTUS 23
106 #define CONTENT_BRICK 24
107 #define CONTENT_CLAY 25
108
109 /*
110         Content feature list
111 */
112
113 enum ContentParamType
114 {
115         CPT_NONE,
116         CPT_LIGHT,
117         CPT_MINERAL,
118         // Direction for chests and furnaces and such
119         CPT_FACEDIR_SIMPLE
120 };
121
122 enum LiquidType
123 {
124         LIQUID_NONE,
125         LIQUID_FLOWING,
126         LIQUID_SOURCE
127 };
128
129 class MapNode;
130 class NodeMetadata;
131
132 struct ContentFeatures
133 {
134         // If non-NULL, content is translated to this when deserialized
135         MapNode *translate_to;
136
137         // Type of MapNode::param
138         ContentParamType param_type;
139
140         /*
141                 0: up
142                 1: down
143                 2: right
144                 3: left
145                 4: back
146                 5: front
147         */
148         TileSpec tiles[6];
149         
150         video::ITexture *inventory_texture;
151
152         bool is_ground_content;
153         bool light_propagates;
154         bool sunlight_propagates;
155         u8 solidness; // Used when choosing which face is drawn
156         // This is used for collision detection.
157         // Also for general solidness queries.
158         bool walkable;
159         // Player can point to these
160         bool pointable;
161         // Player can dig these
162         bool diggable;
163         // Player can build on these
164         bool buildable_to;
165         // Whether the node has no liquid, source liquid or flowing liquid
166         enum LiquidType liquid_type;
167         // If true, param2 is set to direction when placed. Used for torches.
168         // NOTE: the direction format is quite inefficient and should be changed
169         bool wall_mounted;
170         // If true, node is equivalent to air. Torches are, air is. Water is not.
171         // Is used for example to check whether a mud block can have grass on.
172         bool air_equivalent;
173         
174         // Inventory item string as which the node appears in inventory when dug.
175         // Mineral overrides this.
176         std::string dug_item;
177         
178         // Initial metadata is cloned from this
179         NodeMetadata *initial_metadata;
180
181         //TODO: Move more properties here
182
183         ContentFeatures()
184         {
185                 translate_to = NULL;
186                 param_type = CPT_NONE;
187                 inventory_texture = NULL;
188                 is_ground_content = false;
189                 light_propagates = false;
190                 sunlight_propagates = false;
191                 solidness = 2;
192                 walkable = true;
193                 pointable = true;
194                 diggable = true;
195                 buildable_to = false;
196                 liquid_type = LIQUID_NONE;
197                 wall_mounted = false;
198                 air_equivalent = false;
199                 dug_item = "";
200                 initial_metadata = NULL;
201         }
202
203         ~ContentFeatures();
204         
205         /*
206                 Quickhands for simple materials
207         */
208         
209         void setTexture(u16 i, std::string name, u8 alpha=255);
210
211         void setAllTextures(std::string name, u8 alpha=255)
212         {
213                 for(u16 i=0; i<6; i++)
214                 {
215                         setTexture(i, name, alpha);
216                 }
217         }
218
219         void setTile(u16 i, const TileSpec &tile)
220         {
221                 tiles[i] = tile;
222         }
223         void setAllTiles(const TileSpec &tile)
224         {
225                 for(u16 i=0; i<6; i++)
226                 {
227                         setTile(i, tile);
228                 }
229         }
230
231         void setInventoryTexture(std::string imgname);
232         
233         void setInventoryTextureCube(std::string top,
234                         std::string left, std::string right);
235 };
236
237 /*
238         Call this to access the ContentFeature list
239 */
240 ContentFeatures & content_features(u8 i);
241
242 /*
243         If true, the material allows light propagation and brightness is stored
244         in param.
245         NOTE: Don't use, use "content_features(m).whatever" instead
246 */
247 inline bool light_propagates_content(u8 m)
248 {
249         return content_features(m).light_propagates;
250         //return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
251 }
252
253 /*
254         If true, the material allows lossless sunlight propagation.
255         NOTE: It doesn't seem to go through torches regardlessly of this
256         NOTE: Don't use, use "content_features(m).whatever" instead
257 */
258 inline bool sunlight_propagates_content(u8 m)
259 {
260         return content_features(m).sunlight_propagates;
261         //return (m == CONTENT_AIR || m == CONTENT_TORCH);
262 }
263
264 /*
265         On a node-node surface, the material of the node with higher solidness
266         is used for drawing.
267         0: Invisible
268         1: Transparent
269         2: Opaque
270         NOTE: Don't use, use "content_features(m).whatever" instead
271 */
272 inline u8 content_solidness(u8 m)
273 {
274         return content_features(m).solidness;
275         /*// As of now, every pseudo node like torches are added to this
276         if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
277                 return 0;
278         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
279                 return 1;
280         return 2;*/
281 }
282
283 // Objects collide with walkable contents
284 // NOTE: Don't use, use "content_features(m).whatever" instead
285 inline bool content_walkable(u8 m)
286 {
287         return content_features(m).walkable;
288         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
289 }
290
291 // NOTE: Don't use, use "content_features(m).whatever" instead
292 inline bool content_liquid(u8 m)
293 {
294         return content_features(m).liquid_type != LIQUID_NONE;
295         //return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
296 }
297
298 // NOTE: Don't use, use "content_features(m).whatever" instead
299 inline bool content_flowing_liquid(u8 m)
300 {
301         return content_features(m).liquid_type == LIQUID_FLOWING;
302         //return (m == CONTENT_WATER);
303 }
304
305 // NOTE: Don't use, use "content_features(m).whatever" instead
306 inline bool content_liquid_source(u8 m)
307 {
308         return content_features(m).liquid_type == LIQUID_SOURCE;
309         //return (m == CONTENT_WATERSOURCE);
310 }
311
312 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
313 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
314 inline u8 make_liquid_flowing(u8 m)
315 {
316         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
317                 return CONTENT_WATER;
318         assert(0);
319 }
320
321 // Pointable contents can be pointed to in the map
322 // NOTE: Don't use, use "content_features(m).whatever" instead
323 inline bool content_pointable(u8 m)
324 {
325         return content_features(m).pointable;
326         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
327 }
328
329 // NOTE: Don't use, use "content_features(m).whatever" instead
330 inline bool content_diggable(u8 m)
331 {
332         return content_features(m).diggable;
333         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
334 }
335
336 // NOTE: Don't use, use "content_features(m).whatever" instead
337 inline bool content_buildable_to(u8 m)
338 {
339         return content_features(m).buildable_to;
340         //return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
341 }
342
343 /*
344         Returns true for contents that form the base ground that
345         follows the main heightmap
346 */
347 /*inline bool is_ground_content(u8 m)
348 {
349         return content_features(m).is_ground_content;
350 }*/
351
352 /*
353         Nodes make a face if contents differ and solidness differs.
354         Return value:
355                 0: No face
356                 1: Face uses m1's content
357                 2: Face uses m2's content
358 */
359 inline u8 face_contents(u8 m1, u8 m2)
360 {
361         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
362                 return 0;
363         
364         bool contents_differ = (m1 != m2);
365         
366         // Contents don't differ for different forms of same liquid
367         if(content_liquid(m1) && content_liquid(m2)
368                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
369                 contents_differ = false;
370         
371         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
372         bool makes_face = contents_differ && solidness_differs;
373
374         if(makes_face == false)
375                 return 0;
376
377         if(content_solidness(m1) > content_solidness(m2))
378                 return 1;
379         else
380                 return 2;
381 }
382
383 /*
384         Packs directions like (1,0,0), (1,-1,0)
385 */
386 inline u8 packDir(v3s16 dir)
387 {
388         u8 b = 0;
389
390         if(dir.X > 0)
391                 b |= (1<<0);
392         else if(dir.X < 0)
393                 b |= (1<<1);
394
395         if(dir.Y > 0)
396                 b |= (1<<2);
397         else if(dir.Y < 0)
398                 b |= (1<<3);
399
400         if(dir.Z > 0)
401                 b |= (1<<4);
402         else if(dir.Z < 0)
403                 b |= (1<<5);
404         
405         return b;
406 }
407 inline v3s16 unpackDir(u8 b)
408 {
409         v3s16 d(0,0,0);
410
411         if(b & (1<<0))
412                 d.X = 1;
413         else if(b & (1<<1))
414                 d.X = -1;
415
416         if(b & (1<<2))
417                 d.Y = 1;
418         else if(b & (1<<3))
419                 d.Y = -1;
420
421         if(b & (1<<4))
422                 d.Z = 1;
423         else if(b & (1<<5))
424                 d.Z = -1;
425         
426         return d;
427 }
428
429 /*
430         facedir: CPT_FACEDIR_SIMPLE param1 value
431         dir: The face for which stuff is wanted
432         return value: The face from which the stuff is actually found
433 */
434 v3s16 facedir_rotate(u8 facedir, v3s16 dir);
435
436 enum LightBank
437 {
438         LIGHTBANK_DAY,
439         LIGHTBANK_NIGHT
440 };
441
442 /*
443         This is the stuff what the whole world consists of.
444 */
445
446 struct MapNode
447 {
448         // Content
449         u8 d;
450
451         /*
452                 Misc parameter. Initialized to 0.
453                 - For light_propagates() blocks, this is light intensity,
454                   stored logarithmically from 0 to LIGHT_MAX.
455                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
456                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
457         */
458         union
459         {
460                 s8 param;
461                 u8 param1;
462         };
463         
464         /*
465                 The second parameter. Initialized to 0.
466                 E.g. direction for torches and flowing water.
467         */
468         union
469         {
470                 u8 param2;
471                 u8 dir;
472         };
473
474         MapNode(const MapNode & n)
475         {
476                 *this = n;
477         }
478         
479         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
480         {
481                 d = data;
482                 param = a_param;
483                 param2 = a_param2;
484         }
485
486         /*MapNode & operator=(const MapNode &other)
487         {
488                 d = other.d;
489                 param = other.param;
490                 param2 = other.param2;
491                 return *this;
492         }*/
493
494         bool operator==(const MapNode &other)
495         {
496                 return (d == other.d
497                                 && param == other.param
498                                 && param2 == other.param2);
499         }
500
501         bool light_propagates()
502         {
503                 return light_propagates_content(d);
504         }
505         
506         bool sunlight_propagates()
507         {
508                 return sunlight_propagates_content(d);
509         }
510         
511         u8 solidness()
512         {
513                 return content_solidness(d);
514         }
515
516         u8 light_source()
517         {
518                 /*
519                         Note that a block that isn't light_propagates() can be a light source.
520                 */
521                 if(d == CONTENT_TORCH)
522                         return LIGHT_MAX;
523                 
524                 return 0;
525         }
526
527         u8 getLightBanksWithSource()
528         {
529                 // Select the brightest of [light source, propagated light]
530                 u8 lightday = 0;
531                 u8 lightnight = 0;
532                 if(content_features(d).param_type == CPT_LIGHT)
533                 {
534                         lightday = param & 0x0f;
535                         lightnight = (param>>4)&0x0f;
536                 }
537                 if(light_source() > lightday)
538                         lightday = light_source();
539                 if(light_source() > lightnight)
540                         lightnight = light_source();
541                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
542         }
543
544         void setLightBanks(u8 a_light)
545         {
546                 param = a_light;
547         }
548
549         u8 getLight(enum LightBank bank)
550         {
551                 // Select the brightest of [light source, propagated light]
552                 u8 light = 0;
553                 if(content_features(d).param_type == CPT_LIGHT)
554                 {
555                         if(bank == LIGHTBANK_DAY)
556                                 light = param & 0x0f;
557                         else if(bank == LIGHTBANK_NIGHT)
558                                 light = (param>>4)&0x0f;
559                         else
560                                 assert(0);
561                 }
562                 if(light_source() > light)
563                         light = light_source();
564                 return light;
565         }
566         
567         // 0 <= daylight_factor <= 1000
568         // 0 <= return value <= LIGHT_SUN
569         u8 getLightBlend(u32 daylight_factor)
570         {
571                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
572                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
573                         )/1000;
574                 u8 max = LIGHT_MAX;
575                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
576                         max = LIGHT_SUN;
577                 if(l > max)
578                         l = max;
579                 return l;
580         }
581         /*// 0 <= daylight_factor <= 1000
582         // 0 <= return value <= 255
583         u8 getLightBlend(u32 daylight_factor)
584         {
585                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
586                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
587                 u8 mix = ((daylight_factor * daylight
588                         + (1000-daylight_factor) * nightlight)
589                         )/1000;
590                 return mix;
591         }*/
592
593         void setLight(enum LightBank bank, u8 a_light)
594         {
595                 // If node doesn't contain light data, ignore this
596                 if(content_features(d).param_type != CPT_LIGHT)
597                         return;
598                 if(bank == LIGHTBANK_DAY)
599                 {
600                         param &= 0xf0;
601                         param |= a_light & 0x0f;
602                 }
603                 else if(bank == LIGHTBANK_NIGHT)
604                 {
605                         param &= 0x0f;
606                         param |= (a_light & 0x0f)<<4;
607                 }
608                 else
609                         assert(0);
610         }
611         
612         // In mapnode.cpp
613         TileSpec getTile(v3s16 dir);
614
615         u8 getMineral();
616
617         /*
618                 These serialization functions are used when informing client
619                 of a single node add
620         */
621
622         static u32 serializedLength(u8 version)
623         {
624                 if(!ser_ver_supported(version))
625                         throw VersionMismatchException("ERROR: MapNode format not supported");
626                         
627                 if(version == 0)
628                         return 1;
629                 else if(version <= 9)
630                         return 2;
631                 else
632                         return 3;
633         }
634         void serialize(u8 *dest, u8 version)
635         {
636                 if(!ser_ver_supported(version))
637                         throw VersionMismatchException("ERROR: MapNode format not supported");
638                         
639                 if(version == 0)
640                 {
641                         dest[0] = d;
642                 }
643                 else if(version <= 9)
644                 {
645                         dest[0] = d;
646                         dest[1] = param;
647                 }
648                 else
649                 {
650                         dest[0] = d;
651                         dest[1] = param;
652                         dest[2] = param2;
653                 }
654         }
655         void deSerialize(u8 *source, u8 version)
656         {
657                 if(!ser_ver_supported(version))
658                         throw VersionMismatchException("ERROR: MapNode format not supported");
659                         
660                 if(version == 0)
661                 {
662                         d = source[0];
663                 }
664                 else if(version == 1)
665                 {
666                         d = source[0];
667                         // This version doesn't support saved lighting
668                         if(light_propagates() || light_source() > 0)
669                                 param = 0;
670                         else
671                                 param = source[1];
672                 }
673                 else if(version <= 9)
674                 {
675                         d = source[0];
676                         param = source[1];
677                 }
678                 else
679                 {
680                         d = source[0];
681                         param = source[1];
682                         param2 = source[2];
683                 }
684
685                 // Translate deprecated stuff
686                 // NOTE: This doesn't get used because MapBlock handles node
687                 // parameters directly
688                 MapNode *translate_to = content_features(d).translate_to;
689                 if(translate_to)
690                 {
691                         dstream<<"MapNode: WARNING: Translating "<<d<<" to "
692                                         <<translate_to->d<<std::endl;
693                         *this = *translate_to;
694                 }
695         }
696 };
697
698
699
700 #endif
701