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