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