]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.h
SQLite needs to be linked with -ldl on some Linux distros.
[dragonfireclient.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         // Initial metadata is cloned from this
150         NodeMetadata *initial_metadata;
151         
152         // If the content is liquid, this is the flowing version of the liquid.
153         // If content is liquid, this is the same content.
154         content_t liquid_alternative_flowing;
155         // If the content is liquid, this is the source version of the liquid.
156         content_t liquid_alternative_source;
157         // Viscosity for fluid flow, ranging from 1 to 7, with
158         // 1 giving almost instantaneous propagation and 7 being
159         // the slowest possible
160         u8 liquid_viscosity;
161         // Used currently for flowing liquids
162         u8 vertex_alpha;
163         // Special irrlicht material, used sometimes
164         video::SMaterial *special_material;
165         AtlasPointer *special_atlas;
166         
167         // Amount of light the node emits
168         u8 light_source;
169         
170         // Digging properties for different tools
171         DiggingPropertiesList digging_properties;
172
173         u32 damage_per_second;
174         
175         // NOTE: Move relevant properties to here from elsewhere
176
177         void reset()
178         {
179                 param_type = CPT_NONE;
180                 inventory_texture = NULL;
181                 is_ground_content = false;
182                 light_propagates = false;
183                 sunlight_propagates = false;
184                 solidness = 2;
185                 visual_solidness = 0;
186                 walkable = true;
187                 pointable = true;
188                 diggable = true;
189                 climbable = false;
190                 buildable_to = false;
191                 liquid_type = LIQUID_NONE;
192                 wall_mounted = false;
193                 air_equivalent = false;
194                 dug_item = "";
195                 initial_metadata = NULL;
196                 liquid_alternative_flowing = CONTENT_IGNORE;
197                 liquid_alternative_source = CONTENT_IGNORE;
198                 liquid_viscosity = 0;
199                 vertex_alpha = 255;
200                 special_material = NULL;
201                 special_atlas = NULL;
202                 light_source = 0;
203                 digging_properties.clear();
204                 damage_per_second = 0;
205         }
206
207         ContentFeatures()
208         {
209                 reset();
210         }
211
212         ~ContentFeatures();
213         
214         /*
215                 Quickhands for simple materials
216         */
217         
218         void setTexture(u16 i, std::string name, u8 alpha=255);
219
220         void setAllTextures(std::string name, u8 alpha=255)
221         {
222                 for(u16 i=0; i<6; i++)
223                 {
224                         setTexture(i, name, alpha);
225                 }
226                 // Force inventory texture too
227                 setInventoryTexture(name);
228         }
229
230         void setTile(u16 i, const TileSpec &tile)
231         {
232                 tiles[i] = tile;
233         }
234         void setAllTiles(const TileSpec &tile)
235         {
236                 for(u16 i=0; i<6; i++)
237                 {
238                         setTile(i, tile);
239                 }
240         }
241
242         void setInventoryTexture(std::string imgname);
243         
244         void setInventoryTextureCube(std::string top,
245                         std::string left, std::string right);
246 };
247
248 /*
249         Call this to access the ContentFeature list
250 */
251 ContentFeatures & content_features(content_t i);
252 ContentFeatures & content_features(MapNode &n);
253
254 /*
255         Here is a bunch of DEPRECATED functions.
256 */
257
258 /*
259         If true, the material allows light propagation and brightness is stored
260         in param.
261         NOTE: Don't use, use "content_features(m).whatever" instead
262 */
263 inline bool light_propagates_content(content_t m)
264 {
265         return content_features(m).light_propagates;
266 }
267 /*
268         If true, the material allows lossless sunlight propagation.
269         NOTE: It doesn't seem to go through torches regardlessly of this
270         NOTE: Don't use, use "content_features(m).whatever" instead
271 */
272 inline bool sunlight_propagates_content(content_t m)
273 {
274         return content_features(m).sunlight_propagates;
275 }
276 /*
277         On a node-node surface, the material of the node with higher solidness
278         is used for drawing.
279         0: Invisible
280         1: Transparent
281         2: Opaque
282         NOTE: Don't use, use "content_features(m).whatever" instead
283 */
284 inline u8 content_solidness(content_t m)
285 {
286         return content_features(m).solidness;
287 }
288 // Objects collide with walkable contents
289 // NOTE: Don't use, use "content_features(m).whatever" instead
290 inline bool content_walkable(content_t m)
291 {
292         return content_features(m).walkable;
293 }
294 // NOTE: Don't use, use "content_features(m).whatever" instead
295 inline bool content_liquid(content_t m)
296 {
297         return content_features(m).liquid_type != LIQUID_NONE;
298 }
299 // NOTE: Don't use, use "content_features(m).whatever" instead
300 inline bool content_flowing_liquid(content_t m)
301 {
302         return content_features(m).liquid_type == LIQUID_FLOWING;
303 }
304 // NOTE: Don't use, use "content_features(m).whatever" instead
305 inline bool content_liquid_source(content_t m)
306 {
307         return content_features(m).liquid_type == LIQUID_SOURCE;
308 }
309 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
310 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
311 // NOTE: Don't use, use "content_features(m).whatever" instead
312 inline content_t make_liquid_flowing(content_t m)
313 {
314         u8 c = content_features(m).liquid_alternative_flowing;
315         assert(c != CONTENT_IGNORE);
316         return c;
317 }
318 // Pointable contents can be pointed to in the map
319 // NOTE: Don't use, use "content_features(m).whatever" instead
320 inline bool content_pointable(content_t m)
321 {
322         return content_features(m).pointable;
323 }
324 // NOTE: Don't use, use "content_features(m).whatever" instead
325 inline bool content_diggable(content_t m)
326 {
327         return content_features(m).diggable;
328 }
329 // NOTE: Don't use, use "content_features(m).whatever" instead
330 inline bool content_buildable_to(content_t m)
331 {
332         return content_features(m).buildable_to;
333 }
334
335 /*
336         Nodes make a face if contents differ and solidness differs.
337         Return value:
338                 0: No face
339                 1: Face uses m1's content
340                 2: Face uses m2's content
341 */
342 inline u8 face_contents(content_t m1, content_t m2)
343 {
344         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
345                 return 0;
346         
347         bool contents_differ = (m1 != m2);
348         
349         // Contents don't differ for different forms of same liquid
350         if(content_liquid(m1) && content_liquid(m2)
351                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
352                 contents_differ = false;
353         
354         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
355         bool makes_face = contents_differ && solidness_differs;
356
357         if(makes_face == false)
358                 return 0;
359
360         if(content_solidness(m1) > content_solidness(m2))
361                 return 1;
362         else
363                 return 2;
364 }
365
366 /*
367         Packs directions like (1,0,0), (1,-1,0)
368 */
369 inline u8 packDir(v3s16 dir)
370 {
371         u8 b = 0;
372
373         if(dir.X > 0)
374                 b |= (1<<0);
375         else if(dir.X < 0)
376                 b |= (1<<1);
377
378         if(dir.Y > 0)
379                 b |= (1<<2);
380         else if(dir.Y < 0)
381                 b |= (1<<3);
382
383         if(dir.Z > 0)
384                 b |= (1<<4);
385         else if(dir.Z < 0)
386                 b |= (1<<5);
387         
388         return b;
389 }
390 inline v3s16 unpackDir(u8 b)
391 {
392         v3s16 d(0,0,0);
393
394         if(b & (1<<0))
395                 d.X = 1;
396         else if(b & (1<<1))
397                 d.X = -1;
398
399         if(b & (1<<2))
400                 d.Y = 1;
401         else if(b & (1<<3))
402                 d.Y = -1;
403
404         if(b & (1<<4))
405                 d.Z = 1;
406         else if(b & (1<<5))
407                 d.Z = -1;
408         
409         return d;
410 }
411
412 /*
413         facedir: CPT_FACEDIR_SIMPLE param1 value
414         dir: The face for which stuff is wanted
415         return value: The face from which the stuff is actually found
416
417         NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+
418               and Y- too?
419 */
420 v3s16 facedir_rotate(u8 facedir, v3s16 dir);
421
422 enum LightBank
423 {
424         LIGHTBANK_DAY,
425         LIGHTBANK_NIGHT
426 };
427
428 /*
429         Masks for MapNode.param2 of flowing liquids
430  */
431 #define LIQUID_LEVEL_MASK 0x07
432 #define LIQUID_FLOW_DOWN_MASK 0x08
433
434 /* maximum amount of liquid in a block */
435 #define LIQUID_LEVEL_MAX LIQUID_LEVEL_MASK
436 #define LIQUID_LEVEL_SOURCE (LIQUID_LEVEL_MAX+1)
437
438 /*
439         This is the stuff what the whole world consists of.
440 */
441
442
443 struct MapNode
444 {
445         /*
446                 Main content
447                 0x00-0x7f: Short content type
448                 0x80-0xff: Long content type (param2>>4 makes up low bytes)
449         */
450         union
451         {
452                 u8 param0;
453                 //u8 d;
454         };
455
456         /*
457                 Misc parameter. Initialized to 0.
458                 - For light_propagates() blocks, this is light intensity,
459                   stored logarithmically from 0 to LIGHT_MAX.
460                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
461                   - Contains 2 values, day- and night lighting. Each takes 4 bits.
462                 - Mineral content (should be removed from here)
463                 - Uhh... well, most blocks have light or nothing in here.
464         */
465         union
466         {
467                 u8 param1;
468                 //s8 param;
469         };
470         
471         /*
472                 The second parameter. Initialized to 0.
473                 E.g. direction for torches and flowing water.
474                 If param0 >= 0x80, bits 0xf0 of this is extended content type data
475         */
476         union
477         {
478                 u8 param2;
479                 //u8 dir;
480         };
481
482         MapNode(const MapNode & n)
483         {
484                 *this = n;
485         }
486         
487         MapNode(content_t content=CONTENT_AIR, u8 a_param1=0, u8 a_param2=0)
488         {
489                 //param0 = a_param0;
490                 param1 = a_param1;
491                 param2 = a_param2;
492                 // Set after other params because this needs to override part of param2
493                 setContent(content);
494         }
495
496         bool operator==(const MapNode &other)
497         {
498                 return (param0 == other.param0
499                                 && param1 == other.param1
500                                 && param2 == other.param2);
501         }
502         
503         // To be used everywhere
504         content_t getContent()
505         {
506                 if(param0 < 0x80)
507                         return param0;
508                 else
509                         return (param0<<4) + (param2>>4);
510         }
511         void setContent(content_t c)
512         {
513                 if(c < 0x80)
514                 {
515                         if(param0 >= 0x80)
516                                 param2 &= ~(0xf0);
517                         param0 = c;
518                 }
519                 else
520                 {
521                         param0 = c>>4;
522                         param2 &= ~(0xf0);
523                         param2 |= (c&0x0f)<<4;
524                 }
525         }
526         
527         /*
528                 These four are DEPRECATED I guess. -c55
529         */
530         bool light_propagates()
531         {
532                 return light_propagates_content(getContent());
533         }
534         bool sunlight_propagates()
535         {
536                 return sunlight_propagates_content(getContent());
537         }
538         u8 solidness()
539         {
540                 return content_solidness(getContent());
541         }
542         u8 light_source()
543         {
544                 return content_features(*this).light_source;
545         }
546
547         u8 getLightBanksWithSource()
548         {
549                 // Select the brightest of [light source, propagated light]
550                 u8 lightday = 0;
551                 u8 lightnight = 0;
552                 if(content_features(*this).param_type == CPT_LIGHT)
553                 {
554                         lightday = param1 & 0x0f;
555                         lightnight = (param1>>4)&0x0f;
556                 }
557                 if(light_source() > lightday)
558                         lightday = light_source();
559                 if(light_source() > lightnight)
560                         lightnight = light_source();
561                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
562         }
563
564         u8 getLight(enum LightBank bank)
565         {
566                 // Select the brightest of [light source, propagated light]
567                 u8 light = 0;
568                 if(content_features(*this).param_type == CPT_LIGHT)
569                 {
570                         if(bank == LIGHTBANK_DAY)
571                                 light = param1 & 0x0f;
572                         else if(bank == LIGHTBANK_NIGHT)
573                                 light = (param1>>4)&0x0f;
574                         else
575                                 assert(0);
576                 }
577                 if(light_source() > light)
578                         light = light_source();
579                 return light;
580         }
581         
582         // 0 <= daylight_factor <= 1000
583         // 0 <= return value <= LIGHT_SUN
584         u8 getLightBlend(u32 daylight_factor)
585         {
586                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
587                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
588                         )/1000;
589                 u8 max = LIGHT_MAX;
590                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
591                         max = LIGHT_SUN;
592                 if(l > max)
593                         l = max;
594                 return l;
595         }
596         /*// 0 <= daylight_factor <= 1000
597         // 0 <= return value <= 255
598         u8 getLightBlend(u32 daylight_factor)
599         {
600                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
601                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
602                 u8 mix = ((daylight_factor * daylight
603                         + (1000-daylight_factor) * nightlight)
604                         )/1000;
605                 return mix;
606         }*/
607
608         void setLight(enum LightBank bank, u8 a_light)
609         {
610                 // If node doesn't contain light data, ignore this
611                 if(content_features(*this).param_type != CPT_LIGHT)
612                         return;
613                 if(bank == LIGHTBANK_DAY)
614                 {
615                         param1 &= 0xf0;
616                         param1 |= a_light & 0x0f;
617                 }
618                 else if(bank == LIGHTBANK_NIGHT)
619                 {
620                         param1 &= 0x0f;
621                         param1 |= (a_light & 0x0f)<<4;
622                 }
623                 else
624                         assert(0);
625         }
626         
627         // In mapnode.cpp
628         /*
629                 Get tile of a face of the node.
630                 dir: direction of face
631                 Returns: TileSpec. Can contain miscellaneous texture coordinates,
632                          which must be obeyed so that the texture atlas can be used.
633         */
634         TileSpec getTile(v3s16 dir);
635         
636         /*
637                 Gets mineral content of node, if there is any.
638                 MINERAL_NONE if doesn't contain or isn't able to contain mineral.
639         */
640         u8 getMineral();
641         
642         /*
643                 Serialization functions
644         */
645
646         static u32 serializedLength(u8 version);
647         void serialize(u8 *dest, u8 version);
648         void deSerialize(u8 *source, u8 version);
649         
650 };
651
652 /*
653         Gets lighting value at face of node
654         
655         Parameters must consist of air and !air.
656         Order doesn't matter.
657
658         If either of the nodes doesn't exist, light is 0.
659         
660         parameters:
661                 daynight_ratio: 0...1000
662                 n: getNodeParent(p)
663                 n2: getNodeParent(p + face_dir)
664                 face_dir: axis oriented unit vector from p to p2
665         
666         returns encoded light value.
667 */
668 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
669                 v3s16 face_dir);
670
671 #endif
672