]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.h
commit before some radicallish changes to water behavior
[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
30 // Size of node in rendering units
31 #define BS 10
32
33 #define MATERIALS_COUNT 256
34
35 /*
36         Ignored node.
37
38         Anything that stores MapNodes doesn't have to preserve parameters
39         associated with this material.
40         
41         Doesn't create faces with anything and is considered being
42         out-of-map in the game map.
43 */
44 #define MATERIAL_IGNORE 255
45 #define MATERIAL_IGNORE_DEFAULT_PARAM 0
46
47 /*
48         The common material through which the player can walk and which
49         is transparent to light
50 */
51 #define MATERIAL_AIR 254
52
53 /*
54         Materials-todo:
55
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
61 enum Material
62 {
63         MATERIAL_STONE=0,
64
65         MATERIAL_GRASS,
66
67         MATERIAL_WATER,
68
69         MATERIAL_LIGHT,
70
71         MATERIAL_TREE,
72         
73         MATERIAL_LEAVES,
74
75         MATERIAL_GRASS_FOOTSTEPS,
76         
77         MATERIAL_MESE,
78
79         MATERIAL_MUD,
80         
81         // This is set to the number of the actual values in this enum
82         USEFUL_MATERIAL_COUNT
83 };
84
85 /*
86         If true, the material allows light propagation and brightness is stored
87         in param.
88 */
89 inline bool light_propagates_material(u8 m)
90 {
91         return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER);
92 }
93
94 /*
95         If true, the material allows lossless sunlight propagation.
96 */
97 inline bool sunlight_propagates_material(u8 m)
98 {
99         return (m == MATERIAL_AIR);
100 }
101
102 /*
103         On a node-node surface, the material of the node with higher solidness
104         is used for drawing.
105         0: Invisible
106         1: Transparent
107         2: Opaque
108 */
109 inline u8 material_solidness(u8 m)
110 {
111         if(m == MATERIAL_AIR)
112                 return 0;
113         if(m == MATERIAL_WATER)
114                 return 1;
115         return 2;
116 }
117
118 // Objects collide with walkable materials
119 inline bool material_walkable(u8 m)
120 {
121         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
122 }
123
124 // A liquid resists fast movement
125 inline bool material_liquid(u8 m)
126 {
127         return (m == MATERIAL_WATER);
128 }
129
130 // Pointable materials can be pointed to in the map
131 inline bool material_pointable(u8 m)
132 {
133         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
134 }
135
136 inline bool material_diggable(u8 m)
137 {
138         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
139 }
140
141 inline bool material_buildable_to(u8 m)
142 {
143         return (m == MATERIAL_AIR || m == MATERIAL_WATER);
144 }
145
146 /*
147         Nodes make a face if materials differ and solidness differs.
148         Return value:
149                 0: No face
150                 1: Face uses m1's material
151                 2: Face uses m2's material
152 */
153 inline u8 face_materials(u8 m1, u8 m2)
154 {
155         if(m1 == MATERIAL_IGNORE || m2 == MATERIAL_IGNORE)
156                 return 0;
157         
158         bool materials_differ = (m1 != m2);
159         bool solidness_differs = (material_solidness(m1) != material_solidness(m2));
160         bool makes_face = materials_differ && solidness_differs;
161
162         if(makes_face == false)
163                 return 0;
164
165         if(material_solidness(m1) > material_solidness(m2))
166                 return 1;
167         else
168                 return 2;
169 }
170
171 /*
172         Returns true for materials that form the base ground that
173         follows the main heightmap
174 */
175 inline bool is_ground_material(u8 m)
176 {
177         return(
178                 m == MATERIAL_STONE ||
179                 m == MATERIAL_GRASS ||
180                 m == MATERIAL_GRASS_FOOTSTEPS ||
181                 m == MATERIAL_MESE ||
182                 m == MATERIAL_MUD
183         );
184 }
185
186 struct MapNode
187 {
188         //TODO: block type to differ from material
189         //      (e.g. grass edges or something)
190         // block type
191         u8 d;
192
193         /*
194                 Misc parameter. Initialized to 0.
195                 - For light_propagates() blocks, this is light intensity,
196                   stored logarithmically from 0 to LIGHT_MAX.
197                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
198         */
199         s8 param;
200
201         u8 pressure;
202
203         MapNode(const MapNode & n)
204         {
205                 *this = n;
206         }
207         
208         MapNode(u8 data=MATERIAL_AIR, u8 a_param=0, u8 a_pressure=0)
209         {
210                 d = data;
211                 param = a_param;
212                 pressure = a_pressure;
213         }
214
215         bool operator==(const MapNode &other)
216         {
217                 return (d == other.d && param == other.param);
218         }
219
220         bool light_propagates()
221         {
222                 return light_propagates_material(d);
223         }
224         
225         bool sunlight_propagates()
226         {
227                 return sunlight_propagates_material(d);
228         }
229         
230         u8 solidness()
231         {
232                 return material_solidness(d);
233         }
234
235         u8 light_source()
236         {
237                 /*
238                         Note that a block that isn't light_propagates() can be a light source.
239                 */
240                 if(d == MATERIAL_LIGHT)
241                         return LIGHT_MAX;
242                 
243                 return 0;
244         }
245
246         u8 getLight()
247         {
248                 // Select the brightest of [light_source, transparent_light]
249                 u8 light = 0;
250                 if(light_propagates())
251                         light = param & 0x0f;
252                 if(light_source() > light)
253                         light = light_source();
254                 return light;
255         }
256
257         void setLight(u8 a_light)
258         {
259                 // If not transparent, can't set light
260                 if(light_propagates() == false)
261                         return;
262                 param = a_light;
263         }
264
265         /*
266                 These serialization functions are used when informing client
267                 of a single node add
268         */
269
270         static u32 serializedLength(u8 version)
271         {
272                 if(!ser_ver_supported(version))
273                         throw VersionMismatchException("ERROR: MapNode format not supported");
274                         
275                 if(version == 0)
276                         return 1;
277                 else if(version <= 9)
278                         return 2;
279                 else
280                         return 3;
281         }
282         void serialize(u8 *dest, u8 version)
283         {
284                 if(!ser_ver_supported(version))
285                         throw VersionMismatchException("ERROR: MapNode format not supported");
286                         
287                 if(version == 0)
288                 {
289                         dest[0] = d;
290                 }
291                 else if(version <= 9)
292                 {
293                         dest[0] = d;
294                         dest[1] = param;
295                 }
296                 else
297                 {
298                         dest[0] = d;
299                         dest[1] = param;
300                         dest[2] = pressure;
301                 }
302         }
303         void deSerialize(u8 *source, u8 version)
304         {
305                 if(!ser_ver_supported(version))
306                         throw VersionMismatchException("ERROR: MapNode format not supported");
307                         
308                 if(version == 0)
309                 {
310                         d = source[0];
311                 }
312                 else if(version == 1)
313                 {
314                         d = source[0];
315                         // This version doesn't support saved lighting
316                         if(light_propagates() || light_source() > 0)
317                                 param = 0;
318                         else
319                                 param = source[1];
320                 }
321                 else if(version <= 9)
322                 {
323                         d = source[0];
324                         param = source[1];
325                 }
326                 else
327                 {
328                         d = source[0];
329                         param = source[1];
330                         pressure = source[2];
331                 }
332         }
333 };
334
335 /*
336         Returns integer position of the node in given
337         floating point position.
338 */
339 inline v3s16 floatToInt(v3f p)
340 {
341         v3s16 p2(
342                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
343                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
344                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
345         return p2;
346 }
347
348 inline v3f intToFloat(v3s16 p)
349 {
350         v3f p2(
351                 p.X * BS,
352                 p.Y * BS,
353                 p.Z * BS
354         );
355         return p2;
356 }
357
358
359
360 #endif
361