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