Re-add jungles, apple trees
[oweals/minetest.git] / src / scriptapi_common.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_common.h"
22
23 extern "C" {
24 #include "lauxlib.h"
25 }
26
27 #include "script.h"
28 #include "scriptapi_types.h"
29 #include "scriptapi_object.h"
30
31
32 Server* get_server(lua_State *L)
33 {
34         // Get server from registry
35         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
36         Server *server = (Server*)lua_touserdata(L, -1);
37         lua_pop(L, 1);
38         return server;
39 }
40
41 ServerEnvironment* get_env(lua_State *L)
42 {
43         // Get environment from registry
44         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
45         ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1);
46         lua_pop(L, 1);
47         return env;
48 }
49
50 void warn_if_field_exists(lua_State *L, int table,
51                 const char *fieldname, const std::string &message)
52 {
53         lua_getfield(L, table, fieldname);
54         if(!lua_isnil(L, -1)){
55                 infostream<<script_get_backtrace(L)<<std::endl;
56                 infostream<<"WARNING: field \""<<fieldname<<"\": "
57                                 <<message<<std::endl;
58         }
59         lua_pop(L, 1);
60 }
61
62 /*
63         ToolCapabilities
64 */
65
66 ToolCapabilities read_tool_capabilities(
67                 lua_State *L, int table)
68 {
69         ToolCapabilities toolcap;
70         getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
71         getintfield(L, table, "max_drop_level", toolcap.max_drop_level);
72         lua_getfield(L, table, "groupcaps");
73         if(lua_istable(L, -1)){
74                 int table_groupcaps = lua_gettop(L);
75                 lua_pushnil(L);
76                 while(lua_next(L, table_groupcaps) != 0){
77                         // key at index -2 and value at index -1
78                         std::string groupname = luaL_checkstring(L, -2);
79                         if(lua_istable(L, -1)){
80                                 int table_groupcap = lua_gettop(L);
81                                 // This will be created
82                                 ToolGroupCap groupcap;
83                                 // Read simple parameters
84                                 getintfield(L, table_groupcap, "maxlevel", groupcap.maxlevel);
85                                 getintfield(L, table_groupcap, "uses", groupcap.uses);
86                                 // DEPRECATED: maxwear
87                                 float maxwear = 0;
88                                 if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
89                                         if(maxwear != 0)
90                                                 groupcap.uses = 1.0/maxwear;
91                                         else
92                                                 groupcap.uses = 0;
93                                         infostream<<script_get_backtrace(L)<<std::endl;
94                                         infostream<<"WARNING: field \"maxwear\" is deprecated; "
95                                                         <<"should replace with uses=1/maxwear"<<std::endl;
96                                 }
97                                 // Read "times" table
98                                 lua_getfield(L, table_groupcap, "times");
99                                 if(lua_istable(L, -1)){
100                                         int table_times = lua_gettop(L);
101                                         lua_pushnil(L);
102                                         while(lua_next(L, table_times) != 0){
103                                                 // key at index -2 and value at index -1
104                                                 int rating = luaL_checkinteger(L, -2);
105                                                 float time = luaL_checknumber(L, -1);
106                                                 groupcap.times[rating] = time;
107                                                 // removes value, keeps key for next iteration
108                                                 lua_pop(L, 1);
109                                         }
110                                 }
111                                 lua_pop(L, 1);
112                                 // Insert groupcap into toolcap
113                                 toolcap.groupcaps[groupname] = groupcap;
114                         }
115                         // removes value, keeps key for next iteration
116                         lua_pop(L, 1);
117                 }
118         }
119         lua_pop(L, 1);
120         return toolcap;
121 }
122
123 void set_tool_capabilities(lua_State *L, int table,
124                 const ToolCapabilities &toolcap)
125 {
126         setfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval);
127         setintfield(L, table, "max_drop_level", toolcap.max_drop_level);
128         // Create groupcaps table
129         lua_newtable(L);
130         // For each groupcap
131         for(std::map<std::string, ToolGroupCap>::const_iterator
132                         i = toolcap.groupcaps.begin(); i != toolcap.groupcaps.end(); i++){
133                 // Create groupcap table
134                 lua_newtable(L);
135                 const std::string &name = i->first;
136                 const ToolGroupCap &groupcap = i->second;
137                 // Create subtable "times"
138                 lua_newtable(L);
139                 for(std::map<int, float>::const_iterator
140                                 i = groupcap.times.begin(); i != groupcap.times.end(); i++){
141                         int rating = i->first;
142                         float time = i->second;
143                         lua_pushinteger(L, rating);
144                         lua_pushnumber(L, time);
145                         lua_settable(L, -3);
146                 }
147                 // Set subtable "times"
148                 lua_setfield(L, -2, "times");
149                 // Set simple parameters
150                 setintfield(L, -1, "maxlevel", groupcap.maxlevel);
151                 setintfield(L, -1, "uses", groupcap.uses);
152                 // Insert groupcap table into groupcaps table
153                 lua_setfield(L, -2, name.c_str());
154         }
155         // Set groupcaps table
156         lua_setfield(L, -2, "groupcaps");
157 }
158
159 void push_tool_capabilities(lua_State *L,
160                 const ToolCapabilities &prop)
161 {
162         lua_newtable(L);
163         set_tool_capabilities(L, -1, prop);
164 }
165
166 void realitycheck(lua_State *L)
167 {
168         int top = lua_gettop(L);
169         if(top >= 30){
170                 dstream<<"Stack is over 30:"<<std::endl;
171                 stackDump(L, dstream);
172                 script_error(L, "Stack is over 30 (reality check)");
173         }
174 }
175
176 /*
177         PointedThing
178 */
179
180 void push_pointed_thing(lua_State *L, const PointedThing& pointed)
181 {
182         lua_newtable(L);
183         if(pointed.type == POINTEDTHING_NODE)
184         {
185                 lua_pushstring(L, "node");
186                 lua_setfield(L, -2, "type");
187                 push_v3s16(L, pointed.node_undersurface);
188                 lua_setfield(L, -2, "under");
189                 push_v3s16(L, pointed.node_abovesurface);
190                 lua_setfield(L, -2, "above");
191         }
192         else if(pointed.type == POINTEDTHING_OBJECT)
193         {
194                 lua_pushstring(L, "object");
195                 lua_setfield(L, -2, "type");
196                 objectref_get(L, pointed.object_id);
197                 lua_setfield(L, -2, "ref");
198         }
199         else
200         {
201                 lua_pushstring(L, "nothing");
202                 lua_setfield(L, -2, "type");
203         }
204 }
205
206 void stackDump(lua_State *L, std::ostream &o)
207 {
208   int i;
209   int top = lua_gettop(L);
210   for (i = 1; i <= top; i++) {  /* repeat for each level */
211         int t = lua_type(L, i);
212         switch (t) {
213
214           case LUA_TSTRING:  /* strings */
215                 o<<"\""<<lua_tostring(L, i)<<"\"";
216                 break;
217
218           case LUA_TBOOLEAN:  /* booleans */
219                 o<<(lua_toboolean(L, i) ? "true" : "false");
220                 break;
221
222           case LUA_TNUMBER:  /* numbers */ {
223                 char buf[10];
224                 snprintf(buf, 10, "%g", lua_tonumber(L, i));
225                 o<<buf;
226                 break; }
227
228           default:  /* other values */
229                 o<<lua_typename(L, t);
230                 break;
231
232         }
233         o<<" ";
234   }
235   o<<std::endl;
236 }
237
238 #if 0
239 // Dump stack top with the dump2 function
240 static void dump2(lua_State *L, const char *name)
241 {
242         // Dump object (debug)
243         lua_getglobal(L, "dump2");
244         luaL_checktype(L, -1, LUA_TFUNCTION);
245         lua_pushvalue(L, -2); // Get previous stack top as first parameter
246         lua_pushstring(L, name);
247         if(lua_pcall(L, 2, 0, 0))
248                 script_error(L, "error: %s", lua_tostring(L, -1));
249 }
250 #endif
251
252 bool string_to_enum(const EnumString *spec, int &result,
253                 const std::string &str)
254 {
255         const EnumString *esp = spec;
256         while(esp->str){
257                 if(str == std::string(esp->str)){
258                         result = esp->num;
259                         return true;
260                 }
261                 esp++;
262         }
263         return false;
264 }
265
266 /*bool enum_to_string(const EnumString *spec, std::string &result,
267                 int num)
268 {
269         const EnumString *esp = spec;
270         while(esp){
271                 if(num == esp->num){
272                         result = esp->str;
273                         return true;
274                 }
275                 esp++;
276         }
277         return false;
278 }*/
279
280 int getenumfield(lua_State *L, int table,
281                 const char *fieldname, const EnumString *spec, int default_)
282 {
283         int result = default_;
284         string_to_enum(spec, result,
285                         getstringfield_default(L, table, fieldname, ""));
286         return result;
287 }