88e7a0d0a7fabb0e6936221065e4a515b556ea0a
[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 #include "materials.h"
31
32 /*
33         Naming scheme:
34         - Material = irrlicht's Material class
35         - Content = (content_t) content of a node
36         - Tile = TileSpec at some side of a node of some content type
37
38         Content ranges:
39                 0x000...0x07f: param2 is fully usable
40                 0x800...0xfff: param2 lower 4 bytes are free
41 */
42 typedef u16 content_t;
43 #define MAX_CONTENT 0xfff
44
45 /*
46         Initializes all kind of stuff in here.
47         Many things depend on this.
48
49         This accesses g_texturesource; if it is non-NULL, textures are set.
50
51         Client first calls this with g_texturesource=NULL to run some
52         unit tests and stuff, then it runs this again with g_texturesource
53         defined to get the textures.
54
55         Server only calls this once with g_texturesource=NULL.
56 */
57 void init_mapnode();
58
59 /*
60         Ignored node.
61
62         Anything that stores MapNodes doesn't have to preserve parameters
63         associated with this material.
64         
65         Doesn't create faces with anything and is considered being
66         out-of-map in the game map.
67 */
68 //#define CONTENT_IGNORE 255
69 #define CONTENT_IGNORE 127
70 #define CONTENT_IGNORE_DEFAULT_PARAM 0
71
72 /*
73         The common material through which the player can walk and which
74         is transparent to light
75 */
76 //#define CONTENT_AIR 254
77 #define CONTENT_AIR 126
78
79 /*
80         Content feature list
81 */
82
83 enum ContentParamType
84 {
85         CPT_NONE,
86         CPT_LIGHT,
87         CPT_MINERAL,
88         // Direction for chests and furnaces and such
89         CPT_FACEDIR_SIMPLE
90 };
91
92 enum LiquidType
93 {
94         LIQUID_NONE,
95         LIQUID_FLOWING,
96         LIQUID_SOURCE
97 };
98
99 struct MapNode;
100 class NodeMetadata;
101
102 struct ContentFeatures
103 {
104         // Type of MapNode::param1
105         ContentParamType param_type;
106
107         /*
108                 0: up
109                 1: down
110                 2: right
111                 3: left
112                 4: back
113                 5: front
114         */
115         TileSpec tiles[6];
116         
117         video::ITexture *inventory_texture;
118         
119         // True for all ground-like things like stone and mud, false for eg. trees
120         bool is_ground_content;
121         bool light_propagates;
122         bool sunlight_propagates;
123         u8 solidness; // Used when choosing which face is drawn
124         u8 visual_solidness; // When solidness=0, this tells how it looks like
125         // This is used for collision detection.
126         // Also for general solidness queries.
127         bool walkable;
128         // Player can point to these
129         bool pointable;
130         // Player can dig these
131         bool diggable;
132         // Player can climb these
133         bool climbable;
134         // Player can build on these
135         bool buildable_to;
136         // Whether the node has no liquid, source liquid or flowing liquid
137         enum LiquidType liquid_type;
138         // If true, param2 is set to direction when placed. Used for torches.
139         // NOTE: the direction format is quite inefficient and should be changed
140         bool wall_mounted;
141         // If true, node is equivalent to air. Torches are, air is. Water is not.
142         // Is used for example to check whether a mud block can have grass on.
143         bool air_equivalent;
144         
145         // Inventory item string as which the node appears in inventory when dug.
146         // Mineral overrides this.
147         std::string dug_item;
148
149         // Extra dug item and its rarity
150         std::string extra_dug_item;
151         s32 extra_dug_item_rarity;
152         
153         // Initial metadata is cloned from this
154         NodeMetadata *initial_metadata;
155         
156         // If the content is liquid, this is the flowing version of the liquid.
157         // If content is liquid, this is the same content.
158         content_t liquid_alternative_flowing;
159         // If the content is liquid, this is the source version of the liquid.
160         content_t liquid_alternative_source;
161         // Viscosity for fluid flow, ranging from 1 to 7, with
162         // 1 giving almost instantaneous propagation and 7 being
163         // the slowest possible
164         u8 liquid_viscosity;
165         // Used currently for flowing liquids
166         u8 vertex_alpha;
167         // Special irrlicht material, used sometimes
168         video::SMaterial *special_material;
169         AtlasPointer *special_atlas;
170         
171         // Amount of light the node emits
172         u8 light_source;
173         
174         // Digging properties for different tools
175         DiggingPropertiesList digging_properties;
176
177         u32 damage_per_second;
178         
179         // NOTE: Move relevant properties to here from elsewhere
180
181         void reset()
182         {
183                 param_type = CPT_NONE;
184                 inventory_texture = NULL;
185                 is_ground_content = false;
186                 light_propagates = false;
187                 sunlight_propagates = false;
188                 solidness = 2;
189                 visual_solidness = 0;
190                 walkable = true;
191                 pointable = true;
192                 diggable = true;
193                 climbable = false;
194                 buildable_to = false;
195                 liquid_type = LIQUID_NONE;
196                 wall_mounted = false;
197                 air_equivalent = false;
198                 dug_item = "";
199                 initial_metadata = NULL;
200                 liquid_alternative_flowing = CONTENT_IGNORE;
201                 liquid_alternative_source = CONTENT_IGNORE;
202                 liquid_viscosity = 0;
203                 vertex_alpha = 255;
204                 special_material = NULL;
205                 special_atlas = NULL;
206                 light_source = 0;
207                 digging_properties.clear();
208                 damage_per_second = 0;
209         }
210
211         ContentFeatures()
212         {
213                 reset();
214         }
215
216         ~ContentFeatures();
217         
218         /*
219                 Quickhands for simple materials
220         */
221         
222         void setTexture(u16 i, std::string name, u8 alpha=255);
223
224         void setAllTextures(std::string name, u8 alpha=255)
225         {
226                 for(u16 i=0; i<6; i++)
227                 {
228                         setTexture(i, name, alpha);
229                 }
230                 // Force inventory texture too
231                 setInventoryTexture(name);
232         }
233
234         void setTile(u16 i, const TileSpec &tile)
235         {
236                 tiles[i] = tile;
237         }
238         void setAllTiles(const TileSpec &tile)
239         {
240                 for(u16 i=0; i<6; i++)
241                 {
242                         setTile(i, tile);
243                 }
244         }
245
246         void setInventoryTexture(std::string imgname);
247         
248         void setInventoryTextureCube(std::string top,
249                         std::string left, std::string right);
250 };
251
252 /*
253         Call this to access the ContentFeature list
254 */
255 ContentFeatures & content_features(content_t i);
256 ContentFeatures & content_features(MapNode &n);
257
258 /*
259         Here is a bunch of DEPRECATED functions.
260 */
261
262 /*
263         If true, the material allows light propagation and brightness is stored
264         in param.
265         NOTE: Don't use, use "content_features(m).whatever" instead
266 */
267 inline bool light_propagates_content(content_t m)
268 {
269         return content_features(m).light_propagates;
270 }
271 /*
272         If true, the material allows lossless sunlight propagation.
273         NOTE: It doesn't seem to go through torches regardlessly of this
274         NOTE: Don't use, use "content_features(m).whatever" instead
275 */
276 inline bool sunlight_propagates_content(content_t m)
277 {
278         return content_features(m).sunlight_propagates;
279 }
280 /*
281         On a node-node surface, the material of the node with higher solidness
282         is used for drawing.
283         0: Invisible
284         1: Transparent
285         2: Opaque
286         NOTE: Don't use, use "content_features(m).whatever" instead
287 */
288 inline u8 content_solidness(content_t m)
289 {
290         return content_features(m).solidness;
291 }
292 // Objects collide with walkable contents
293 // NOTE: Don't use, use "content_features(m).whatever" instead
294 inline bool content_walkable(content_t m)
295 {
296         return content_features(m).walkable;
297 }
298 // NOTE: Don't use, use "content_features(m).whatever" instead
299 inline bool content_liquid(content_t m)
300 {
301         return content_features(m).liquid_type != LIQUID_NONE;
302 }
303 // NOTE: Don't use, use "content_features(m).whatever" instead
304 inline bool content_flowing_liquid(content_t m)
305 {
306         return content_features(m).liquid_type == LIQUID_FLOWING;
307 }
308 // NOTE: Don't use, use "content_features(m).whatever" instead
309 inline bool content_liquid_source(content_t m)
310 {
311         return content_features(m).liquid_type == LIQUID_SOURCE;
312 }
313 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
314 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
315 // NOTE: Don't use, use "content_features(m).whatever" instead
316 inline content_t make_liquid_flowing(content_t m)
317 {
318         u8 c = content_features(m).liquid_alternative_flowing;
319         assert(c != CONTENT_IGNORE);
320         return c;
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(content_t m)
325 {
326         return content_features(m).pointable;
327 }
328 // NOTE: Don't use, use "content_features(m).whatever" instead
329 inline bool content_diggable(content_t m)
330 {
331         return content_features(m).diggable;
332 }
333 // NOTE: Don't use, use "content_features(m).whatever" instead
334 inline bool content_buildable_to(content_t m)
335 {
336         return content_features(m).buildable_to;
337 }
338
339 /*
340         Nodes make a face if contents differ and solidness differs.
341         Return value:
342                 0: No face
343                 1: Face uses m1's content
344                 2: Face uses m2's content
345 */
346 inline u8 face_contents(content_t m1, content_t m2)
347 {
348         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
349                 return 0;
350         
351         bool contents_differ = (m1 != m2);
352         
353         // Contents don't differ for different forms of same liquid
354         if(content_liquid(m1) && content_liquid(m2)
355                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
356                 contents_differ = false;
357         
358         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
359         bool makes_face = contents_differ && solidness_differs;
360
361         if(makes_face == false)
362                 return 0;
363
364         if(content_solidness(m1) > content_solidness(m2))
365                 return 1;
366         else
367                 return 2;
368 }
369
370 /*
371         Packs directions like (1,0,0), (1,-1,0)
372 */
373 inline u8 packDir(v3s16 dir)
374 {
375         u8 b = 0;
376
377         if(dir.X > 0)
378                 b |= (1<<0);
379         else if(dir.X < 0)
380                 b |= (1<<1);
381
382         if(dir.Y > 0)
383                 b |= (1<<2);
384         else if(dir.Y < 0)
385                 b |= (1<<3);
386
387         if(dir.Z > 0)
388                 b |= (1<<4);
389         else if(dir.Z < 0)
390                 b |= (1<<5);
391         
392         return b;
393 }
394 inline v3s16 unpackDir(u8 b)
395 {
396         v3s16 d(0,0,0);
397
398         if(b & (1<<0))
399                 d.X = 1;
400         else if(b & (1<<1))
401                 d.X = -1;
402
403         if(b & (1<<2))
404                 d.Y = 1;
405         else if(b & (1<<3))
406                 d.Y = -1;
407
408         if(b & (1<<4))
409                 d.Z = 1;
410         else if(b & (1<<5))
411                 d.Z = -1;
412         
413         return d;
414 }
415
416 /*
417         facedir: CPT_FACEDIR_SIMPLE param1 value
418         dir: The face for which stuff is wanted
419         return value: The face from which the stuff is actually found
420
421         NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+
422               and Y- too?
423 */
424 v3s16 facedir_rotate(u8 facedir, v3s16 dir);
425
426 enum LightBank
427 {
428         LIGHTBANK_DAY,
429         LIGHTBANK_NIGHT
430 };
431
432 /*
433         Masks for MapNode.param2 of flowing liquids
434  */
435 #define LIQUID_LEVEL_MASK 0x07
436 #define LIQUID_FLOW_DOWN_MASK 0x08
437
438 /* maximum amount of liquid in a block */
439 #define LIQUID_LEVEL_MAX LIQUID_LEVEL_MASK
440 #define LIQUID_LEVEL_SOURCE (LIQUID_LEVEL_MAX+1)
441
442 /*
443         This is the stuff what the whole world consists of.
444 */
445
446
447 struct MapNode
448 {
449         /*
450                 Main content
451                 0x00-0x7f: Short content type
452                 0x80-0xff: Long content type (param2>>4 makes up low bytes)
453         */
454         union
455         {
456                 u8 param0;
457                 //u8 d;
458         };
459
460         /*
461                 Misc parameter. Initialized to 0.
462                 - For light_propagates() blocks, this is light intensity,
463                   stored logarithmically from 0 to LIGHT_MAX.
464                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
465                   - Contains 2 values, day- and night lighting. Each takes 4 bits.
466                 - Mineral content (should be removed from here)
467                 - Uhh... well, most blocks have light or nothing in here.
468         */
469         union
470         {
471                 u8 param1;
472                 //s8 param;
473         };
474         
475         /*
476                 The second parameter. Initialized to 0.
477                 E.g. direction for torches and flowing water.
478                 If param0 >= 0x80, bits 0xf0 of this is extended content type data
479         */
480         union
481         {
482                 u8 param2;
483                 //u8 dir;
484         };
485
486         MapNode(const MapNode & n)
487         {
488                 *this = n;
489         }
490         
491         MapNode(content_t content=CONTENT_AIR, u8 a_param1=0, u8 a_param2=0)
492         {
493                 //param0 = a_param0;
494                 param1 = a_param1;
495                 param2 = a_param2;
496                 // Set after other params because this needs to override part of param2
497                 setContent(content);
498         }
499
500         bool operator==(const MapNode &other)
501         {
502                 return (param0 == other.param0
503                                 && param1 == other.param1
504                                 && param2 == other.param2);
505         }
506         
507         // To be used everywhere
508         content_t getContent()
509         {
510                 if(param0 < 0x80)
511                         return param0;
512                 else
513                         return (param0<<4) + (param2>>4);
514         }
515         void setContent(content_t c)
516         {
517                 if(c < 0x80)
518                 {
519                         if(param0 >= 0x80)
520                                 param2 &= ~(0xf0);
521                         param0 = c;
522                 }
523                 else
524                 {
525                         param0 = c>>4;
526                         param2 &= ~(0xf0);
527                         param2 |= (c&0x0f)<<4;
528                 }
529         }
530         
531         /*
532                 These four are DEPRECATED I guess. -c55
533         */
534         bool light_propagates()
535         {
536                 return light_propagates_content(getContent());
537         }
538         bool sunlight_propagates()
539         {
540                 return sunlight_propagates_content(getContent());
541         }
542         u8 solidness()
543         {
544                 return content_solidness(getContent());
545         }
546         u8 light_source()
547         {
548                 return content_features(*this).light_source;
549         }
550
551         u8 getLightBanksWithSource()
552         {
553                 // Select the brightest of [light source, propagated light]
554                 u8 lightday = 0;
555                 u8 lightnight = 0;
556                 if(content_features(*this).param_type == CPT_LIGHT)
557                 {
558                         lightday = param1 & 0x0f;
559                         lightnight = (param1>>4)&0x0f;
560                 }
561                 if(light_source() > lightday)
562                         lightday = light_source();
563                 if(light_source() > lightnight)
564                         lightnight = light_source();
565                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
566         }
567
568         u8 getLight(enum LightBank bank)
569         {
570                 // Select the brightest of [light source, propagated light]
571                 u8 light = 0;
572                 if(content_features(*this).param_type == CPT_LIGHT)
573                 {
574                         if(bank == LIGHTBANK_DAY)
575                                 light = param1 & 0x0f;
576                         else if(bank == LIGHTBANK_NIGHT)
577                                 light = (param1>>4)&0x0f;
578                         else
579                                 assert(0);
580                 }
581                 if(light_source() > light)
582                         light = light_source();
583                 return light;
584         }
585         
586         // 0 <= daylight_factor <= 1000
587         // 0 <= return value <= LIGHT_SUN
588         u8 getLightBlend(u32 daylight_factor)
589         {
590                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
591                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
592                         )/1000;
593                 u8 max = LIGHT_MAX;
594                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
595                         max = LIGHT_SUN;
596                 if(l > max)
597                         l = max;
598                 return l;
599         }
600         /*// 0 <= daylight_factor <= 1000
601         // 0 <= return value <= 255
602         u8 getLightBlend(u32 daylight_factor)
603         {
604                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
605                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
606                 u8 mix = ((daylight_factor * daylight
607                         + (1000-daylight_factor) * nightlight)
608                         )/1000;
609                 return mix;
610         }*/
611
612         void setLight(enum LightBank bank, u8 a_light)
613         {
614                 // If node doesn't contain light data, ignore this
615                 if(content_features(*this).param_type != CPT_LIGHT)
616                         return;
617                 if(bank == LIGHTBANK_DAY)
618                 {
619                         param1 &= 0xf0;
620                         param1 |= a_light & 0x0f;
621                 }
622                 else if(bank == LIGHTBANK_NIGHT)
623                 {
624                         param1 &= 0x0f;
625                         param1 |= (a_light & 0x0f)<<4;
626                 }
627                 else
628                         assert(0);
629         }
630         
631         // In mapnode.cpp
632         /*
633                 Get tile of a face of the node.
634                 dir: direction of face
635                 Returns: TileSpec. Can contain miscellaneous texture coordinates,
636                          which must be obeyed so that the texture atlas can be used.
637         */
638         TileSpec getTile(v3s16 dir);
639         
640         /*
641                 Gets mineral content of node, if there is any.
642                 MINERAL_NONE if doesn't contain or isn't able to contain mineral.
643         */
644         u8 getMineral();
645         
646         /*
647                 Serialization functions
648         */
649
650         static u32 serializedLength(u8 version);
651         void serialize(u8 *dest, u8 version);
652         void deSerialize(u8 *source, u8 version);
653         
654 };
655
656 /*
657         Gets lighting value at face of node
658         
659         Parameters must consist of air and !air.
660         Order doesn't matter.
661
662         If either of the nodes doesn't exist, light is 0.
663         
664         parameters:
665                 daynight_ratio: 0...1000
666                 n: getNodeParent(p)
667                 n2: getNodeParent(p + face_dir)
668                 face_dir: axis oriented unit vector from p to p2
669         
670         returns encoded light value.
671 */
672 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
673                 v3s16 face_dir);
674
675 #endif
676