Merge remote-tracking branch 'origin/master'
[oweals/minetest.git] / src / scriptapi_content.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #include "scriptapi.h"
21 #include "scriptapi_content.h"
22 #include "scriptapi_types.h"
23 #include "scriptapi_common.h"
24 #include "scriptapi_node.h"
25
26
27 NodeBox read_nodebox(lua_State *L, int index)
28 {
29         NodeBox nodebox;
30         if(lua_istable(L, -1)){
31                 nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
32                                 es_NodeBoxType, NODEBOX_REGULAR);
33
34                 lua_getfield(L, index, "fixed");
35                 if(lua_istable(L, -1))
36                         nodebox.fixed = read_aabb3f_vector(L, -1, BS);
37                 lua_pop(L, 1);
38
39                 lua_getfield(L, index, "wall_top");
40                 if(lua_istable(L, -1))
41                         nodebox.wall_top = read_aabb3f(L, -1, BS);
42                 lua_pop(L, 1);
43
44                 lua_getfield(L, index, "wall_bottom");
45                 if(lua_istable(L, -1))
46                         nodebox.wall_bottom = read_aabb3f(L, -1, BS);
47                 lua_pop(L, 1);
48
49                 lua_getfield(L, index, "wall_side");
50                 if(lua_istable(L, -1))
51                         nodebox.wall_side = read_aabb3f(L, -1, BS);
52                 lua_pop(L, 1);
53         }
54         return nodebox;
55 }
56
57 /*
58         SimpleSoundSpec
59 */
60
61 void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec)
62 {
63         if(index < 0)
64                 index = lua_gettop(L) + 1 + index;
65         if(lua_isnil(L, index)){
66         } else if(lua_istable(L, index)){
67                 getstringfield(L, index, "name", spec.name);
68                 getfloatfield(L, index, "gain", spec.gain);
69         } else if(lua_isstring(L, index)){
70                 spec.name = lua_tostring(L, index);
71         }
72 }
73
74 struct EnumString es_TileAnimationType[] =
75 {
76         {TAT_NONE, "none"},
77         {TAT_VERTICAL_FRAMES, "vertical_frames"},
78         {0, NULL},
79 };
80
81 /*
82         TileDef
83 */
84
85 TileDef read_tiledef(lua_State *L, int index)
86 {
87         if(index < 0)
88                 index = lua_gettop(L) + 1 + index;
89
90         TileDef tiledef;
91
92         // key at index -2 and value at index
93         if(lua_isstring(L, index)){
94                 // "default_lava.png"
95                 tiledef.name = lua_tostring(L, index);
96         }
97         else if(lua_istable(L, index))
98         {
99                 // {name="default_lava.png", animation={}}
100                 tiledef.name = "";
101                 getstringfield(L, index, "name", tiledef.name);
102                 getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
103                 tiledef.backface_culling = getboolfield_default(
104                                         L, index, "backface_culling", true);
105                 // animation = {}
106                 lua_getfield(L, index, "animation");
107                 if(lua_istable(L, -1)){
108                         // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
109                         tiledef.animation.type = (TileAnimationType)
110                                         getenumfield(L, -1, "type", es_TileAnimationType,
111                                         TAT_NONE);
112                         tiledef.animation.aspect_w =
113                                         getintfield_default(L, -1, "aspect_w", 16);
114                         tiledef.animation.aspect_h =
115                                         getintfield_default(L, -1, "aspect_h", 16);
116                         tiledef.animation.length =
117                                         getfloatfield_default(L, -1, "length", 1.0);
118                 }
119                 lua_pop(L, 1);
120         }
121
122         return tiledef;
123 }
124
125 /*
126         ContentFeatures
127 */
128
129 ContentFeatures read_content_features(lua_State *L, int index)
130 {
131         if(index < 0)
132                 index = lua_gettop(L) + 1 + index;
133
134         ContentFeatures f;
135
136         /* Cache existence of some callbacks */
137         lua_getfield(L, index, "on_construct");
138         if(!lua_isnil(L, -1)) f.has_on_construct = true;
139         lua_pop(L, 1);
140         lua_getfield(L, index, "on_destruct");
141         if(!lua_isnil(L, -1)) f.has_on_destruct = true;
142         lua_pop(L, 1);
143         lua_getfield(L, index, "after_destruct");
144         if(!lua_isnil(L, -1)) f.has_after_destruct = true;
145         lua_pop(L, 1);
146
147         lua_getfield(L, index, "on_rightclick");
148         f.rightclickable = lua_isfunction(L, -1);
149         lua_pop(L, 1);
150         
151         /* Name */
152         getstringfield(L, index, "name", f.name);
153
154         /* Groups */
155         lua_getfield(L, index, "groups");
156         read_groups(L, -1, f.groups);
157         lua_pop(L, 1);
158
159         /* Visual definition */
160
161         f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
162                         NDT_NORMAL);
163         getfloatfield(L, index, "visual_scale", f.visual_scale);
164
165         // tiles = {}
166         lua_getfield(L, index, "tiles");
167         // If nil, try the deprecated name "tile_images" instead
168         if(lua_isnil(L, -1)){
169                 lua_pop(L, 1);
170                 warn_if_field_exists(L, index, "tile_images",
171                                 "Deprecated; new name is \"tiles\".");
172                 lua_getfield(L, index, "tile_images");
173         }
174         if(lua_istable(L, -1)){
175                 int table = lua_gettop(L);
176                 lua_pushnil(L);
177                 int i = 0;
178                 while(lua_next(L, table) != 0){
179                         // Read tiledef from value
180                         f.tiledef[i] = read_tiledef(L, -1);
181                         // removes value, keeps key for next iteration
182                         lua_pop(L, 1);
183                         i++;
184                         if(i==6){
185                                 lua_pop(L, 1);
186                                 break;
187                         }
188                 }
189                 // Copy last value to all remaining textures
190                 if(i >= 1){
191                         TileDef lasttile = f.tiledef[i-1];
192                         while(i < 6){
193                                 f.tiledef[i] = lasttile;
194                                 i++;
195                         }
196                 }
197         }
198         lua_pop(L, 1);
199
200         // special_tiles = {}
201         lua_getfield(L, index, "special_tiles");
202         // If nil, try the deprecated name "special_materials" instead
203         if(lua_isnil(L, -1)){
204                 lua_pop(L, 1);
205                 warn_if_field_exists(L, index, "special_materials",
206                                 "Deprecated; new name is \"special_tiles\".");
207                 lua_getfield(L, index, "special_materials");
208         }
209         if(lua_istable(L, -1)){
210                 int table = lua_gettop(L);
211                 lua_pushnil(L);
212                 int i = 0;
213                 while(lua_next(L, table) != 0){
214                         // Read tiledef from value
215                         f.tiledef_special[i] = read_tiledef(L, -1);
216                         // removes value, keeps key for next iteration
217                         lua_pop(L, 1);
218                         i++;
219                         if(i==6){
220                                 lua_pop(L, 1);
221                                 break;
222                         }
223                 }
224         }
225         lua_pop(L, 1);
226
227         f.alpha = getintfield_default(L, index, "alpha", 255);
228         
229         bool usealpha = getboolfield_default(L, index,
230                                                 "use_texture_alpha", false);
231         if (usealpha)
232                 f.alpha = 0;
233
234         /* Other stuff */
235
236         lua_getfield(L, index, "post_effect_color");
237         if(!lua_isnil(L, -1))
238                 f.post_effect_color = readARGB8(L, -1);
239         lua_pop(L, 1);
240
241         f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
242                         es_ContentParamType, CPT_NONE);
243         f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
244                         es_ContentParamType2, CPT2_NONE);
245
246         // Warn about some deprecated fields
247         warn_if_field_exists(L, index, "wall_mounted",
248                         "deprecated: use paramtype2 = 'wallmounted'");
249         warn_if_field_exists(L, index, "light_propagates",
250                         "deprecated: determined from paramtype");
251         warn_if_field_exists(L, index, "dug_item",
252                         "deprecated: use 'drop' field");
253         warn_if_field_exists(L, index, "extra_dug_item",
254                         "deprecated: use 'drop' field");
255         warn_if_field_exists(L, index, "extra_dug_item_rarity",
256                         "deprecated: use 'drop' field");
257         warn_if_field_exists(L, index, "metadata_name",
258                         "deprecated: use on_add and metadata callbacks");
259
260         // True for all ground-like things like stone and mud, false for eg. trees
261         getboolfield(L, index, "is_ground_content", f.is_ground_content);
262         f.light_propagates = (f.param_type == CPT_LIGHT);
263         getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates);
264         // This is used for collision detection.
265         // Also for general solidness queries.
266         getboolfield(L, index, "walkable", f.walkable);
267         // Player can point to these
268         getboolfield(L, index, "pointable", f.pointable);
269         // Player can dig these
270         getboolfield(L, index, "diggable", f.diggable);
271         // Player can climb these
272         getboolfield(L, index, "climbable", f.climbable);
273         // Player can build on these
274         getboolfield(L, index, "buildable_to", f.buildable_to);
275         // Whether the node is non-liquid, source liquid or flowing liquid
276         f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
277                         es_LiquidType, LIQUID_NONE);
278         // If the content is liquid, this is the flowing version of the liquid.
279         getstringfield(L, index, "liquid_alternative_flowing",
280                         f.liquid_alternative_flowing);
281         // If the content is liquid, this is the source version of the liquid.
282         getstringfield(L, index, "liquid_alternative_source",
283                         f.liquid_alternative_source);
284         // Viscosity for fluid flow, ranging from 1 to 7, with
285         // 1 giving almost instantaneous propagation and 7 being
286         // the slowest possible
287         f.liquid_viscosity = getintfield_default(L, index,
288                         "liquid_viscosity", f.liquid_viscosity);
289         getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
290         // Amount of light the node emits
291         f.light_source = getintfield_default(L, index,
292                         "light_source", f.light_source);
293         f.damage_per_second = getintfield_default(L, index,
294                         "damage_per_second", f.damage_per_second);
295
296         lua_getfield(L, index, "node_box");
297         if(lua_istable(L, -1))
298                 f.node_box = read_nodebox(L, -1);
299         lua_pop(L, 1);
300
301         lua_getfield(L, index, "selection_box");
302         if(lua_istable(L, -1))
303                 f.selection_box = read_nodebox(L, -1);
304         lua_pop(L, 1);
305
306         // Set to true if paramtype used to be 'facedir_simple'
307         getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple);
308         // Set to true if wall_mounted used to be set to true
309         getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted);
310
311         // Sound table
312         lua_getfield(L, index, "sounds");
313         if(lua_istable(L, -1)){
314                 lua_getfield(L, -1, "footstep");
315                 read_soundspec(L, -1, f.sound_footstep);
316                 lua_pop(L, 1);
317                 lua_getfield(L, -1, "dig");
318                 read_soundspec(L, -1, f.sound_dig);
319                 lua_pop(L, 1);
320                 lua_getfield(L, -1, "dug");
321                 read_soundspec(L, -1, f.sound_dug);
322                 lua_pop(L, 1);
323         }
324         lua_pop(L, 1);
325
326         return f;
327 }