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