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