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