]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.h
mud placed in sunlight no longer instantly turns to grass; also tuned transforming...
[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
31 /*
32         Initializes all kind of stuff in here.
33         Many things depend on this.
34
35         This accesses g_texturesource; if it is non-NULL, textures are set.
36
37         Client first calls this with g_texturesource=NULL to run some
38         unit tests and stuff, then it runs this again with g_texturesource
39         defined to get the textures.
40
41         Server only calls this once with g_texturesource=NULL.
42 */
43 void init_mapnode();
44
45 // Initializes g_content_inventory_texture_paths
46 void init_content_inventory_texture_paths();
47
48
49 // NOTE: This is not used appropriately everywhere.
50 #define MATERIALS_COUNT 256
51
52 /*
53         Ignored node.
54
55         Anything that stores MapNodes doesn't have to preserve parameters
56         associated with this material.
57         
58         Doesn't create faces with anything and is considered being
59         out-of-map in the game map.
60 */
61 #define CONTENT_IGNORE 255
62 #define CONTENT_IGNORE_DEFAULT_PARAM 0
63
64 /*
65         The common material through which the player can walk and which
66         is transparent to light
67 */
68 #define CONTENT_AIR 254
69
70 /*
71         Suggested materials:
72         - Gravel
73         - Sand
74         
75         New naming scheme:
76         - Material = irrlicht's Material class
77         - Content = (u8) content of a node
78         - Tile = (u16) Material ID at some side of a node
79 */
80
81 #define CONTENT_STONE 0
82 #define CONTENT_GRASS 1
83 #define CONTENT_WATER 2
84 #define CONTENT_TORCH 3
85 #define CONTENT_TREE 4
86 #define CONTENT_LEAVES 5
87 #define CONTENT_GRASS_FOOTSTEPS 6
88 #define CONTENT_MESE 7
89 #define CONTENT_MUD 8
90 #define CONTENT_WATERSOURCE 9
91 // Pretty much useless, clouds won't be drawn this way
92 #define CONTENT_CLOUD 10
93 #define CONTENT_COALSTONE 11
94 #define CONTENT_WOOD 12
95 #define CONTENT_SAND 13
96 #define CONTENT_SIGN_WALL 14
97 #define CONTENT_CHEST 15
98 #define CONTENT_FURNACE 16
99 //#define CONTENT_WORKBENCH 17
100 #define CONTENT_COBBLE 18
101 #define CONTENT_STEEL 19
102 #define CONTENT_GLASS 20
103
104 /*
105         Content feature list
106 */
107
108 enum ContentParamType
109 {
110         CPT_NONE,
111         CPT_LIGHT,
112         CPT_MINERAL,
113         // Direction for chests and furnaces and such
114         CPT_FACEDIR_SIMPLE
115 };
116
117 enum LiquidType
118 {
119         LIQUID_NONE,
120         LIQUID_FLOWING,
121         LIQUID_SOURCE
122 };
123
124 class MapNode;
125 class NodeMetadata;
126
127 struct ContentFeatures
128 {
129         // If non-NULL, content is translated to this when deserialized
130         MapNode *translate_to;
131
132         // Type of MapNode::param
133         ContentParamType param_type;
134
135         /*
136                 0: up
137                 1: down
138                 2: right
139                 3: left
140                 4: back
141                 5: front
142         */
143         TileSpec tiles[6];
144         
145         video::ITexture *inventory_texture;
146
147         bool is_ground_content;
148         bool light_propagates;
149         bool sunlight_propagates;
150         u8 solidness; // Used when choosing which face is drawn
151         // This is used for collision detection.
152         // Also for general solidness queries.
153         bool walkable;
154         bool pointable;
155         bool diggable;
156         bool buildable_to;
157         enum LiquidType liquid_type;
158         // If true, param2 is set to direction when placed
159         // NOTE: the direction format is quite inefficient and should be changed
160         bool wall_mounted;
161         
162         // Inventory item string as which the node appears in inventory when dug.
163         // Mineral overrides this.
164         std::string dug_item;
165         
166         // Initial metadata is cloned from this
167         NodeMetadata *initial_metadata;
168
169         //TODO: Move more properties here
170
171         ContentFeatures()
172         {
173                 translate_to = NULL;
174                 param_type = CPT_NONE;
175                 inventory_texture = NULL;
176                 is_ground_content = false;
177                 light_propagates = false;
178                 sunlight_propagates = false;
179                 solidness = 2;
180                 walkable = true;
181                 pointable = true;
182                 diggable = true;
183                 buildable_to = false;
184                 liquid_type = LIQUID_NONE;
185                 wall_mounted = false;
186                 dug_item = "";
187                 initial_metadata = NULL;
188         }
189
190         ~ContentFeatures();
191         
192         /*
193                 Quickhands for simple materials
194         */
195         
196         void setTexture(u16 i, std::string name, u8 alpha=255);
197
198         void setAllTextures(std::string name, u8 alpha=255)
199         {
200                 for(u16 i=0; i<6; i++)
201                 {
202                         setTexture(i, name, alpha);
203                 }
204         }
205
206         void setTile(u16 i, const TileSpec &tile)
207         {
208                 tiles[i] = tile;
209         }
210         void setAllTiles(const TileSpec &tile)
211         {
212                 for(u16 i=0; i<6; i++)
213                 {
214                         setTile(i, tile);
215                 }
216         }
217
218         void setInventoryTexture(std::string imgname);
219         
220         void setInventoryTextureCube(std::string top,
221                         std::string left, std::string right);
222 };
223
224 /*
225         Call this to access the ContentFeature list
226 */
227 ContentFeatures & content_features(u8 i);
228
229 /*
230         If true, the material allows light propagation and brightness is stored
231         in param.
232         NOTE: Don't use, use "content_features(m).whatever" instead
233 */
234 inline bool light_propagates_content(u8 m)
235 {
236         return content_features(m).light_propagates;
237         //return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
238 }
239
240 /*
241         If true, the material allows lossless sunlight propagation.
242         NOTE: It doesn't seem to go through torches regardlessly of this
243         NOTE: Don't use, use "content_features(m).whatever" instead
244 */
245 inline bool sunlight_propagates_content(u8 m)
246 {
247         return content_features(m).sunlight_propagates;
248         //return (m == CONTENT_AIR || m == CONTENT_TORCH);
249 }
250
251 /*
252         On a node-node surface, the material of the node with higher solidness
253         is used for drawing.
254         0: Invisible
255         1: Transparent
256         2: Opaque
257         NOTE: Don't use, use "content_features(m).whatever" instead
258 */
259 inline u8 content_solidness(u8 m)
260 {
261         return content_features(m).solidness;
262         /*// As of now, every pseudo node like torches are added to this
263         if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
264                 return 0;
265         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
266                 return 1;
267         return 2;*/
268 }
269
270 // Objects collide with walkable contents
271 // NOTE: Don't use, use "content_features(m).whatever" instead
272 inline bool content_walkable(u8 m)
273 {
274         return content_features(m).walkable;
275         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
276 }
277
278 // NOTE: Don't use, use "content_features(m).whatever" instead
279 inline bool content_liquid(u8 m)
280 {
281         return content_features(m).liquid_type != LIQUID_NONE;
282         //return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
283 }
284
285 // NOTE: Don't use, use "content_features(m).whatever" instead
286 inline bool content_flowing_liquid(u8 m)
287 {
288         return content_features(m).liquid_type == LIQUID_FLOWING;
289         //return (m == CONTENT_WATER);
290 }
291
292 // NOTE: Don't use, use "content_features(m).whatever" instead
293 inline bool content_liquid_source(u8 m)
294 {
295         return content_features(m).liquid_type == LIQUID_SOURCE;
296         //return (m == CONTENT_WATERSOURCE);
297 }
298
299 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
300 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
301 inline u8 make_liquid_flowing(u8 m)
302 {
303         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
304                 return CONTENT_WATER;
305         assert(0);
306 }
307
308 // Pointable contents can be pointed to in the map
309 // NOTE: Don't use, use "content_features(m).whatever" instead
310 inline bool content_pointable(u8 m)
311 {
312         return content_features(m).pointable;
313         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
314 }
315
316 // NOTE: Don't use, use "content_features(m).whatever" instead
317 inline bool content_diggable(u8 m)
318 {
319         return content_features(m).diggable;
320         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
321 }
322
323 // NOTE: Don't use, use "content_features(m).whatever" instead
324 inline bool content_buildable_to(u8 m)
325 {
326         return content_features(m).buildable_to;
327         //return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
328 }
329
330 /*
331         Returns true for contents that form the base ground that
332         follows the main heightmap
333 */
334 /*inline bool is_ground_content(u8 m)
335 {
336         return content_features(m).is_ground_content;
337 }*/
338
339 /*
340         Nodes make a face if contents differ and solidness differs.
341         Return value:
342                 0: No face
343                 1: Face uses m1's content
344                 2: Face uses m2's content
345 */
346 inline u8 face_contents(u8 m1, u8 m2)
347 {
348         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
349                 return 0;
350         
351         bool contents_differ = (m1 != m2);
352         
353         // Contents don't differ for different forms of same liquid
354         if(content_liquid(m1) && content_liquid(m2)
355                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
356                 contents_differ = false;
357         
358         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
359         bool makes_face = contents_differ && solidness_differs;
360
361         if(makes_face == false)
362                 return 0;
363
364         if(content_solidness(m1) > content_solidness(m2))
365                 return 1;
366         else
367                 return 2;
368 }
369
370 /*
371         Packs directions like (1,0,0), (1,-1,0)
372 */
373 inline u8 packDir(v3s16 dir)
374 {
375         u8 b = 0;
376
377         if(dir.X > 0)
378                 b |= (1<<0);
379         else if(dir.X < 0)
380                 b |= (1<<1);
381
382         if(dir.Y > 0)
383                 b |= (1<<2);
384         else if(dir.Y < 0)
385                 b |= (1<<3);
386
387         if(dir.Z > 0)
388                 b |= (1<<4);
389         else if(dir.Z < 0)
390                 b |= (1<<5);
391         
392         return b;
393 }
394 inline v3s16 unpackDir(u8 b)
395 {
396         v3s16 d(0,0,0);
397
398         if(b & (1<<0))
399                 d.X = 1;
400         else if(b & (1<<1))
401                 d.X = -1;
402
403         if(b & (1<<2))
404                 d.Y = 1;
405         else if(b & (1<<3))
406                 d.Y = -1;
407
408         if(b & (1<<4))
409                 d.Z = 1;
410         else if(b & (1<<5))
411                 d.Z = -1;
412         
413         return d;
414 }
415
416 /*
417         facedir: CPT_FACEDIR_SIMPLE param1 value
418         dir: The face for which stuff is wanted
419         return value: The face from which the stuff is actually found
420 */
421 v3s16 facedir_rotate(u8 facedir, v3s16 dir);
422
423 enum LightBank
424 {
425         LIGHTBANK_DAY,
426         LIGHTBANK_NIGHT
427 };
428
429 /*
430         This is the stuff what the whole world consists of.
431 */
432
433 struct MapNode
434 {
435         // Content
436         u8 d;
437
438         /*
439                 Misc parameter. Initialized to 0.
440                 - For light_propagates() blocks, this is light intensity,
441                   stored logarithmically from 0 to LIGHT_MAX.
442                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
443                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
444         */
445         union
446         {
447                 s8 param;
448                 u8 param1;
449         };
450         
451         /*
452                 The second parameter. Initialized to 0.
453                 E.g. direction for torches and flowing water.
454         */
455         union
456         {
457                 u8 param2;
458                 u8 dir;
459         };
460
461         MapNode(const MapNode & n)
462         {
463                 *this = n;
464         }
465         
466         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
467         {
468                 d = data;
469                 param = a_param;
470                 param2 = a_param2;
471         }
472
473         /*MapNode & operator=(const MapNode &other)
474         {
475                 d = other.d;
476                 param = other.param;
477                 param2 = other.param2;
478                 return *this;
479         }*/
480
481         bool operator==(const MapNode &other)
482         {
483                 return (d == other.d
484                                 && param == other.param
485                                 && param2 == other.param2);
486         }
487
488         bool light_propagates()
489         {
490                 return light_propagates_content(d);
491         }
492         
493         bool sunlight_propagates()
494         {
495                 return sunlight_propagates_content(d);
496         }
497         
498         u8 solidness()
499         {
500                 return content_solidness(d);
501         }
502
503         u8 light_source()
504         {
505                 /*
506                         Note that a block that isn't light_propagates() can be a light source.
507                 */
508                 if(d == CONTENT_TORCH)
509                         return LIGHT_MAX;
510                 
511                 return 0;
512         }
513
514         u8 getLightBanksWithSource()
515         {
516                 // Select the brightest of [light source, propagated light]
517                 u8 lightday = 0;
518                 u8 lightnight = 0;
519                 if(content_features(d).param_type == CPT_LIGHT)
520                 {
521                         lightday = param & 0x0f;
522                         lightnight = (param>>4)&0x0f;
523                 }
524                 if(light_source() > lightday)
525                         lightday = light_source();
526                 if(light_source() > lightnight)
527                         lightnight = light_source();
528                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
529         }
530
531         void setLightBanks(u8 a_light)
532         {
533                 param = a_light;
534         }
535
536         u8 getLight(enum LightBank bank)
537         {
538                 // Select the brightest of [light source, propagated light]
539                 u8 light = 0;
540                 if(content_features(d).param_type == CPT_LIGHT)
541                 {
542                         if(bank == LIGHTBANK_DAY)
543                                 light = param & 0x0f;
544                         else if(bank == LIGHTBANK_NIGHT)
545                                 light = (param>>4)&0x0f;
546                         else
547                                 assert(0);
548                 }
549                 if(light_source() > light)
550                         light = light_source();
551                 return light;
552         }
553         
554         // 0 <= daylight_factor <= 1000
555         // 0 <= return value <= LIGHT_SUN
556         u8 getLightBlend(u32 daylight_factor)
557         {
558                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
559                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
560                         )/1000;
561                 u8 max = LIGHT_MAX;
562                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
563                         max = LIGHT_SUN;
564                 if(l > max)
565                         l = max;
566                 return l;
567         }
568         /*// 0 <= daylight_factor <= 1000
569         // 0 <= return value <= 255
570         u8 getLightBlend(u32 daylight_factor)
571         {
572                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
573                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
574                 u8 mix = ((daylight_factor * daylight
575                         + (1000-daylight_factor) * nightlight)
576                         )/1000;
577                 return mix;
578         }*/
579
580         void setLight(enum LightBank bank, u8 a_light)
581         {
582                 // If node doesn't contain light data, ignore this
583                 if(content_features(d).param_type != CPT_LIGHT)
584                         return;
585                 if(bank == LIGHTBANK_DAY)
586                 {
587                         param &= 0xf0;
588                         param |= a_light & 0x0f;
589                 }
590                 else if(bank == LIGHTBANK_NIGHT)
591                 {
592                         param &= 0x0f;
593                         param |= (a_light & 0x0f)<<4;
594                 }
595                 else
596                         assert(0);
597         }
598         
599         // In mapnode.cpp
600         TileSpec getTile(v3s16 dir);
601
602         u8 getMineral();
603
604         /*
605                 These serialization functions are used when informing client
606                 of a single node add
607         */
608
609         static u32 serializedLength(u8 version)
610         {
611                 if(!ser_ver_supported(version))
612                         throw VersionMismatchException("ERROR: MapNode format not supported");
613                         
614                 if(version == 0)
615                         return 1;
616                 else if(version <= 9)
617                         return 2;
618                 else
619                         return 3;
620         }
621         void serialize(u8 *dest, u8 version)
622         {
623                 if(!ser_ver_supported(version))
624                         throw VersionMismatchException("ERROR: MapNode format not supported");
625                         
626                 if(version == 0)
627                 {
628                         dest[0] = d;
629                 }
630                 else if(version <= 9)
631                 {
632                         dest[0] = d;
633                         dest[1] = param;
634                 }
635                 else
636                 {
637                         dest[0] = d;
638                         dest[1] = param;
639                         dest[2] = param2;
640                 }
641         }
642         void deSerialize(u8 *source, u8 version)
643         {
644                 if(!ser_ver_supported(version))
645                         throw VersionMismatchException("ERROR: MapNode format not supported");
646                         
647                 if(version == 0)
648                 {
649                         d = source[0];
650                 }
651                 else if(version == 1)
652                 {
653                         d = source[0];
654                         // This version doesn't support saved lighting
655                         if(light_propagates() || light_source() > 0)
656                                 param = 0;
657                         else
658                                 param = source[1];
659                 }
660                 else if(version <= 9)
661                 {
662                         d = source[0];
663                         param = source[1];
664                 }
665                 else
666                 {
667                         d = source[0];
668                         param = source[1];
669                         param2 = source[2];
670                 }
671
672                 // Translate deprecated stuff
673                 // NOTE: This doesn't get used because MapBlock handles node
674                 // parameters directly
675                 MapNode *translate_to = content_features(d).translate_to;
676                 if(translate_to)
677                 {
678                         dstream<<"MapNode: WARNING: Translating "<<d<<" to "
679                                         <<translate_to->d<<std::endl;
680                         *this = *translate_to;
681                 }
682         }
683 };
684
685
686
687 #endif
688