]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.h
removed alternative name "pressure" from param2
[minetest.git] / src / mapnode.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 #define MATERIALS_COUNT 256
32
33 /*
34         Ignored node.
35
36         Anything that stores MapNodes doesn't have to preserve parameters
37         associated with this material.
38         
39         Doesn't create faces with anything and is considered being
40         out-of-map in the game map.
41 */
42 #define CONTENT_IGNORE 255
43 #define CONTENT_IGNORE_DEFAULT_PARAM 0
44
45 /*
46         The common material through which the player can walk and which
47         is transparent to light
48 */
49 #define CONTENT_AIR 254
50
51 /*
52         Suggested materials:
53         - Gravel
54         - Sand
55         
56         New naming scheme:
57         - Material = irrlicht's Material class
58         - Content = (u8) content of a node
59         - Tile = (u16) Material ID at some side of a node
60 */
61
62 #define CONTENT_STONE 0
63 #define CONTENT_GRASS 1
64 #define CONTENT_WATER 2
65 #define CONTENT_TORCH 3
66 #define CONTENT_TREE 4
67 #define CONTENT_LEAVES 5
68 #define CONTENT_GRASS_FOOTSTEPS 6
69 #define CONTENT_MESE 7
70 #define CONTENT_MUD 8
71 #define CONTENT_WATERSOURCE 9
72 #define CONTENT_CLOUD 10
73 #define CONTENT_COALSTONE 11
74 #define CONTENT_WOOD 12
75         
76 #define USEFUL_CONTENT_COUNT 13
77
78 extern u16 g_content_tiles[USEFUL_CONTENT_COUNT][6];
79 extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
80 // Initializes g_content_inventory_texture_paths
81 void init_content_inventory_texture_paths();
82
83 /*
84         If true, the material allows light propagation and brightness is stored
85         in param.
86 */
87 inline bool light_propagates_content(u8 m)
88 {
89         return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
90 }
91
92 /*
93         If true, the material allows lossless sunlight propagation.
94         NOTE: It doesn't seem to go through torches regardlessly of this
95 */
96 inline bool sunlight_propagates_content(u8 m)
97 {
98         return (m == CONTENT_AIR || m == CONTENT_TORCH);
99 }
100
101 /*
102         On a node-node surface, the material of the node with higher solidness
103         is used for drawing.
104         0: Invisible
105         1: Transparent
106         2: Opaque
107 */
108 inline u8 content_solidness(u8 m)
109 {
110         // As of now, every pseudo node like torches are added to this
111         if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
112                 return 0;
113         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
114                 return 1;
115         return 2;
116 }
117
118 // Objects collide with walkable contents
119 inline bool content_walkable(u8 m)
120 {
121         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
122 }
123
124 inline bool content_liquid(u8 m)
125 {
126         return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
127 }
128
129 inline bool content_flowing_liquid(u8 m)
130 {
131         return (m == CONTENT_WATER);
132 }
133
134 inline bool content_liquid_source(u8 m)
135 {
136         return (m == CONTENT_WATERSOURCE);
137 }
138
139 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
140 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
141 inline u8 make_liquid_flowing(u8 m)
142 {
143         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
144                 return CONTENT_WATER;
145         assert(0);
146 }
147
148 // Pointable contents can be pointed to in the map
149 inline bool content_pointable(u8 m)
150 {
151         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
152 }
153
154 inline bool content_diggable(u8 m)
155 {
156         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
157 }
158
159 inline bool content_buildable_to(u8 m)
160 {
161         return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
162 }
163
164 /*
165         Returns true for contents that form the base ground that
166         follows the main heightmap
167 */
168 inline bool is_ground_content(u8 m)
169 {
170         return (
171                 m != CONTENT_IGNORE
172                 && m != CONTENT_AIR
173                 && m != CONTENT_WATER
174                 && m != CONTENT_TORCH
175                 && m != CONTENT_TREE
176                 && m != CONTENT_LEAVES
177                 && m != CONTENT_WATERSOURCE
178                 && m != CONTENT_CLOUD
179         );
180 }
181
182 inline bool is_mineral(u8 c)
183 {
184         return(c == CONTENT_MESE
185                 || c == CONTENT_COALSTONE);
186 }
187
188 inline bool liquid_replaces_content(u8 c)
189 {
190         return (c == CONTENT_AIR || c == CONTENT_TORCH);
191 }
192
193 /*
194         When placing a node, drection info is added to it if this is true
195 */
196 inline bool content_directional(u8 c)
197 {
198         return (c == CONTENT_TORCH);
199 }
200
201 /*
202         Nodes make a face if contents differ and solidness differs.
203         Return value:
204                 0: No face
205                 1: Face uses m1's content
206                 2: Face uses m2's content
207 */
208 inline u8 face_contents(u8 m1, u8 m2)
209 {
210         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
211                 return 0;
212         
213         bool contents_differ = (m1 != m2);
214         
215         // Contents don't differ for different forms of same liquid
216         if(content_liquid(m1) && content_liquid(m2)
217                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
218                 contents_differ = false;
219         
220         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
221         bool makes_face = contents_differ && solidness_differs;
222
223         if(makes_face == false)
224                 return 0;
225
226         if(content_solidness(m1) > content_solidness(m2))
227                 return 1;
228         else
229                 return 2;
230 }
231
232 /*
233         Packs directions like (1,0,0), (1,-1,0)
234 */
235 inline u8 packDir(v3s16 dir)
236 {
237         u8 b = 0;
238
239         if(dir.X > 0)
240                 b |= (1<<0);
241         else if(dir.X < 0)
242                 b |= (1<<1);
243
244         if(dir.Y > 0)
245                 b |= (1<<2);
246         else if(dir.Y < 0)
247                 b |= (1<<3);
248
249         if(dir.Z > 0)
250                 b |= (1<<4);
251         else if(dir.Z < 0)
252                 b |= (1<<5);
253         
254         return b;
255 }
256 inline v3s16 unpackDir(u8 b)
257 {
258         v3s16 d(0,0,0);
259
260         if(b & (1<<0))
261                 d.X = 1;
262         else if(b & (1<<1))
263                 d.X = -1;
264
265         if(b & (1<<2))
266                 d.Y = 1;
267         else if(b & (1<<3))
268                 d.Y = -1;
269
270         if(b & (1<<4))
271                 d.Z = 1;
272         else if(b & (1<<5))
273                 d.Z = -1;
274         
275         return d;
276 }
277
278 inline u16 content_tile(u8 c, v3s16 dir)
279 {
280         if(c == CONTENT_IGNORE || c == CONTENT_AIR
281                         || c >= USEFUL_CONTENT_COUNT)
282                 return TILE_NONE;
283
284         s32 dir_i = -1;
285         
286         if(dir == v3s16(0,1,0))
287                 dir_i = 0;
288         else if(dir == v3s16(0,-1,0))
289                 dir_i = 1;
290         else if(dir == v3s16(1,0,0))
291                 dir_i = 2;
292         else if(dir == v3s16(-1,0,0))
293                 dir_i = 3;
294         else if(dir == v3s16(0,0,1))
295                 dir_i = 4;
296         else if(dir == v3s16(0,0,-1))
297                 dir_i = 5;
298         
299         /*if(dir_i == -1)
300                 return TILE_NONE;*/
301         assert(dir_i != -1);
302
303         return g_content_tiles[c][dir_i];
304 }
305
306 enum LightBank
307 {
308         LIGHTBANK_DAY,
309         LIGHTBANK_NIGHT
310 };
311
312 #if 0
313 #define DIR_PX 1 //X+
314 #define DIR_NX 2 //X-
315 #define DIR_PZ 4 //Z+
316 #define DIR_NZ 8 //Z-
317 #define DIR_PY 16 //Y+
318 #define DIR_NY 32 //Y-
319
320 inline void decode_dirs(u8 b, core::list<v3s16> &dirs)
321 {
322         if(b & DIR_PX)
323                 dirs.push_back(v3s16(1,0,0));
324         if(b & DIR_NX)
325                 dirs.push_back(v3s16(-1,0,0));
326         if(b & DIR_PZ)
327                 dirs.push_back(v3s16(0,0,1));
328         if(b & DIR_NZ)
329                 dirs.push_back(v3s16(0,0,-1));
330         if(b & DIR_PY)
331                 dirs.push_back(v3s16(0,1,0));
332         if(b & DIR_NY)
333                 dirs.push_back(v3s16(0,-1,0));
334 }
335
336 inline u8 encode_dirs(core::list<v3s16> &dirs)
337 {
338         u8 b = 0;
339         for(core::list<v3s16>::Iterator
340                         i = dirs.begin();
341                         i != dirs.end(); i++)
342         {
343                 if(*i == v3s16(1,0,0))
344                         b += DIR_PX;
345                 else if(*i == v3s16(-1,0,0))
346                         b += DIR_NX;
347                 else if(*i == v3s16(0,0,1))
348                         b += DIR_PZ;
349                 else if(*i == v3s16(0,0,-1))
350                         b += DIR_NZ;
351                 else if(*i == v3s16(0,1,0))
352                         b += DIR_PY;
353                 else if(*i == v3s16(0,-1,0))
354                         b += DIR_NY;
355         }
356         return b;
357 }
358 #endif
359
360 struct MapNode
361 {
362         // Content
363         u8 d;
364
365         /*
366                 Misc parameter. Initialized to 0.
367                 - For light_propagates() blocks, this is light intensity,
368                   stored logarithmically from 0 to LIGHT_MAX.
369                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
370                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
371         */
372         s8 param;
373         
374         union
375         {
376                 u8 param2;
377
378                 /*
379                         Direction for torches and other stuff.
380                         Format is freeform. e.g. packDir or encode_dirs can be used.
381                 */
382                 u8 dir;
383         };
384
385         MapNode(const MapNode & n)
386         {
387                 *this = n;
388         }
389         
390         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
391         {
392                 d = data;
393                 param = a_param;
394                 param2 = a_param2;
395         }
396
397         bool operator==(const MapNode &other)
398         {
399                 return (d == other.d
400                                 && param == other.param
401                                 && param2 == other.param2);
402         }
403
404         bool light_propagates()
405         {
406                 return light_propagates_content(d);
407         }
408         
409         bool sunlight_propagates()
410         {
411                 return sunlight_propagates_content(d);
412         }
413         
414         u8 solidness()
415         {
416                 return content_solidness(d);
417         }
418
419         u8 light_source()
420         {
421                 /*
422                         Note that a block that isn't light_propagates() can be a light source.
423                 */
424                 if(d == CONTENT_TORCH)
425                         return LIGHT_MAX;
426                 
427                 return 0;
428         }
429
430         u8 getLightBanksWithSource()
431         {
432                 // Select the brightest of [light source, propagated light]
433                 u8 lightday = 0;
434                 u8 lightnight = 0;
435                 if(light_propagates())
436                 {
437                         lightday = param & 0x0f;
438                         lightnight = (param>>4)&0x0f;
439                 }
440                 if(light_source() > lightday)
441                         lightday = light_source();
442                 if(light_source() > lightnight)
443                         lightnight = light_source();
444                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
445         }
446
447         void setLightBanks(u8 a_light)
448         {
449                 param = a_light;
450         }
451
452         u8 getLight(enum LightBank bank)
453         {
454                 // Select the brightest of [light source, propagated light]
455                 u8 light = 0;
456                 if(light_propagates())
457                 {
458                         if(bank == LIGHTBANK_DAY)
459                                 light = param & 0x0f;
460                         else if(bank == LIGHTBANK_NIGHT)
461                                 light = (param>>4)&0x0f;
462                         else
463                                 assert(0);
464                 }
465                 if(light_source() > light)
466                         light = light_source();
467                 return light;
468         }
469         
470         // 0 <= daylight_factor <= 1000
471         // 0 <= return value <= LIGHT_SUN
472         u8 getLightBlend(u32 daylight_factor)
473         {
474                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
475                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
476                         )/1000;
477                 u8 max = LIGHT_MAX;
478                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
479                         max = LIGHT_SUN;
480                 if(l > max)
481                         l = max;
482                 return l;
483         }
484         /*// 0 <= daylight_factor <= 1000
485         // 0 <= return value <= 255
486         u8 getLightBlend(u32 daylight_factor)
487         {
488                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
489                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
490                 u8 mix = ((daylight_factor * daylight
491                         + (1000-daylight_factor) * nightlight)
492                         )/1000;
493                 return mix;
494         }*/
495
496         void setLight(enum LightBank bank, u8 a_light)
497         {
498                 // If not transparent, can't set light
499                 if(light_propagates() == false)
500                         return;
501                 if(bank == LIGHTBANK_DAY)
502                 {
503                         param &= 0xf0;
504                         param |= a_light & 0x0f;
505                 }
506                 else if(bank == LIGHTBANK_NIGHT)
507                 {
508                         param &= 0x0f;
509                         param |= (a_light & 0x0f)<<4;
510                 }
511                 else
512                         assert(0);
513         }
514
515         u16 getTile(v3s16 dir)
516         {
517                 return content_tile(d, dir);
518         }
519
520         /*
521                 These serialization functions are used when informing client
522                 of a single node add
523         */
524
525         static u32 serializedLength(u8 version)
526         {
527                 if(!ser_ver_supported(version))
528                         throw VersionMismatchException("ERROR: MapNode format not supported");
529                         
530                 if(version == 0)
531                         return 1;
532                 else if(version <= 9)
533                         return 2;
534                 else
535                         return 3;
536         }
537         void serialize(u8 *dest, u8 version)
538         {
539                 if(!ser_ver_supported(version))
540                         throw VersionMismatchException("ERROR: MapNode format not supported");
541                         
542                 if(version == 0)
543                 {
544                         dest[0] = d;
545                 }
546                 else if(version <= 9)
547                 {
548                         dest[0] = d;
549                         dest[1] = param;
550                 }
551                 else
552                 {
553                         dest[0] = d;
554                         dest[1] = param;
555                         dest[2] = param2;
556                 }
557         }
558         void deSerialize(u8 *source, u8 version)
559         {
560                 if(!ser_ver_supported(version))
561                         throw VersionMismatchException("ERROR: MapNode format not supported");
562                         
563                 if(version == 0)
564                 {
565                         d = source[0];
566                 }
567                 else if(version == 1)
568                 {
569                         d = source[0];
570                         // This version doesn't support saved lighting
571                         if(light_propagates() || light_source() > 0)
572                                 param = 0;
573                         else
574                                 param = source[1];
575                 }
576                 else if(version <= 9)
577                 {
578                         d = source[0];
579                         param = source[1];
580                 }
581                 else
582                 {
583                         d = source[0];
584                         param = source[1];
585                         param2 = source[2];
586                 }
587         }
588 };
589
590 /*
591         Returns integer position of the node in given
592         floating point position.
593 */
594 inline v3s16 floatToInt(v3f p)
595 {
596         v3s16 p2(
597                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
598                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
599                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
600         return p2;
601 }
602
603 inline v3f intToFloat(v3s16 p)
604 {
605         v3f p2(
606                 p.X * BS,
607                 p.Y * BS,
608                 p.Z * BS
609         );
610         return p2;
611 }
612
613
614
615 #endif
616