]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/cpp_api/s_entity.cpp
Fix damage wraparound if very high damage (#11872)
[dragonfireclient.git] / src / script / cpp_api / s_entity.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 "cpp_api/s_entity.h"
21 #include "cpp_api/s_internal.h"
22 #include "log.h"
23 #include "object_properties.h"
24 #include "common/c_converter.h"
25 #include "common/c_content.h"
26 #include "server.h"
27
28 bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
29 {
30         SCRIPTAPI_PRECHECKHEADER
31
32         verbosestream<<"scriptapi_luaentity_add: id="<<id<<" name=\""
33                         <<name<<"\""<<std::endl;
34
35         // Get core.registered_entities[name]
36         lua_getglobal(L, "core");
37         lua_getfield(L, -1, "registered_entities");
38         luaL_checktype(L, -1, LUA_TTABLE);
39         lua_pushstring(L, name);
40         lua_gettable(L, -2);
41         // Should be a table, which we will use as a prototype
42         //luaL_checktype(L, -1, LUA_TTABLE);
43         if (lua_type(L, -1) != LUA_TTABLE){
44                 errorstream<<"LuaEntity name \""<<name<<"\" not defined"<<std::endl;
45                 return false;
46         }
47         int prototype_table = lua_gettop(L);
48         //dump2(L, "prototype_table");
49
50         // Create entity object
51         lua_newtable(L);
52         int object = lua_gettop(L);
53
54         // Set object metatable
55         lua_pushvalue(L, prototype_table);
56         lua_setmetatable(L, -2);
57
58         // Add object reference
59         // This should be userdata with metatable ObjectRef
60         push_objectRef(L, id);
61         luaL_checktype(L, -1, LUA_TUSERDATA);
62         if (!luaL_checkudata(L, -1, "ObjectRef"))
63                 luaL_typerror(L, -1, "ObjectRef");
64         lua_setfield(L, -2, "object");
65
66         // core.luaentities[id] = object
67         lua_getglobal(L, "core");
68         lua_getfield(L, -1, "luaentities");
69         luaL_checktype(L, -1, LUA_TTABLE);
70         lua_pushnumber(L, id); // Push id
71         lua_pushvalue(L, object); // Copy object to top of stack
72         lua_settable(L, -3);
73
74         return true;
75 }
76
77 void ScriptApiEntity::luaentity_Activate(u16 id,
78                 const std::string &staticdata, u32 dtime_s)
79 {
80         SCRIPTAPI_PRECHECKHEADER
81
82         verbosestream << "scriptapi_luaentity_activate: id=" << id << std::endl;
83
84         int error_handler = PUSH_ERROR_HANDLER(L);
85
86         // Get core.luaentities[id]
87         luaentity_get(L, id);
88         int object = lua_gettop(L);
89
90         // Get on_activate function
91         lua_getfield(L, -1, "on_activate");
92         if (!lua_isnil(L, -1)) {
93                 luaL_checktype(L, -1, LUA_TFUNCTION);
94                 lua_pushvalue(L, object); // self
95                 lua_pushlstring(L, staticdata.c_str(), staticdata.size());
96                 lua_pushinteger(L, dtime_s);
97
98                 setOriginFromTable(object);
99                 PCALL_RES(lua_pcall(L, 3, 0, error_handler));
100         } else {
101                 lua_pop(L, 1);
102         }
103         lua_pop(L, 2); // Pop object and error handler
104 }
105
106 void ScriptApiEntity::luaentity_Deactivate(u16 id)
107 {
108         SCRIPTAPI_PRECHECKHEADER
109
110         verbosestream << "scriptapi_luaentity_deactivate: id=" << id << std::endl;
111
112         int error_handler = PUSH_ERROR_HANDLER(L);
113
114         // Get the entity
115         luaentity_get(L, id);
116         int object = lua_gettop(L);
117
118         // Get on_deactivate
119         lua_getfield(L, -1, "on_deactivate");
120         if (!lua_isnil(L, -1)) {
121                 luaL_checktype(L, -1, LUA_TFUNCTION);
122                 lua_pushvalue(L, object);
123
124                 setOriginFromTable(object);
125                 PCALL_RES(lua_pcall(L, 1, 0, error_handler));
126         } else {
127                 lua_pop(L, 1);
128         }
129         lua_pop(L, 2); // Pop object and error handler
130 }
131
132 void ScriptApiEntity::luaentity_Remove(u16 id)
133 {
134         SCRIPTAPI_PRECHECKHEADER
135
136         verbosestream << "scriptapi_luaentity_rm: id=" << id << std::endl;
137
138         // Get core.luaentities table
139         lua_getglobal(L, "core");
140         lua_getfield(L, -1, "luaentities");
141         luaL_checktype(L, -1, LUA_TTABLE);
142         int objectstable = lua_gettop(L);
143
144         // Set luaentities[id] = nil
145         lua_pushnumber(L, id); // Push id
146         lua_pushnil(L);
147         lua_settable(L, objectstable);
148
149         lua_pop(L, 2); // pop luaentities, core
150 }
151
152 std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
153 {
154         SCRIPTAPI_PRECHECKHEADER
155
156         //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
157
158         int error_handler = PUSH_ERROR_HANDLER(L);
159
160         // Get core.luaentities[id]
161         luaentity_get(L, id);
162         int object = lua_gettop(L);
163
164         // Get get_staticdata function
165         lua_getfield(L, -1, "get_staticdata");
166         if (lua_isnil(L, -1)) {
167                 lua_pop(L, 2); // Pop entity and  get_staticdata
168                 return "";
169         }
170         luaL_checktype(L, -1, LUA_TFUNCTION);
171         lua_pushvalue(L, object); // self
172
173         setOriginFromTable(object);
174         PCALL_RES(lua_pcall(L, 1, 1, error_handler));
175
176         lua_remove(L, object);
177         lua_remove(L, error_handler);
178
179         size_t len = 0;
180         const char *s = lua_tolstring(L, -1, &len);
181         lua_pop(L, 1); // Pop static data
182         return std::string(s, len);
183 }
184
185 void ScriptApiEntity::luaentity_GetProperties(u16 id,
186                 ServerActiveObject *self, ObjectProperties *prop)
187 {
188         SCRIPTAPI_PRECHECKHEADER
189
190         //infostream<<"scriptapi_luaentity_get_properties: id="<<id<<std::endl;
191
192         // Get core.luaentities[id]
193         luaentity_get(L, id);
194
195         // Set default values that differ from ObjectProperties defaults
196         prop->hp_max = 10;
197
198         // Deprecated: read object properties directly
199         read_object_properties(L, -1, self, prop, getServer()->idef());
200
201         // Read initial_properties
202         lua_getfield(L, -1, "initial_properties");
203         read_object_properties(L, -1, self, prop, getServer()->idef());
204         lua_pop(L, 1);
205 }
206
207 void ScriptApiEntity::luaentity_Step(u16 id, float dtime,
208         const collisionMoveResult *moveresult)
209 {
210         SCRIPTAPI_PRECHECKHEADER
211
212         int error_handler = PUSH_ERROR_HANDLER(L);
213
214         // Get core.luaentities[id]
215         luaentity_get(L, id);
216         int object = lua_gettop(L);
217         // State: object is at top of stack
218         // Get step function
219         lua_getfield(L, -1, "on_step");
220         if (lua_isnil(L, -1)) {
221                 lua_pop(L, 2); // Pop on_step and entity
222                 return;
223         }
224         luaL_checktype(L, -1, LUA_TFUNCTION);
225         lua_pushvalue(L, object); // self
226         lua_pushnumber(L, dtime); // dtime
227         /* moveresult */
228         if (moveresult)
229                 push_collision_move_result(L, *moveresult);
230         else
231                 lua_pushnil(L);
232
233         setOriginFromTable(object);
234         PCALL_RES(lua_pcall(L, 3, 0, error_handler));
235
236         lua_pop(L, 2); // Pop object and error handler
237 }
238
239 // Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
240 //                       tool_capabilities, direction, damage)
241 bool ScriptApiEntity::luaentity_Punch(u16 id,
242                 ServerActiveObject *puncher, float time_from_last_punch,
243                 const ToolCapabilities *toolcap, v3f dir, s32 damage)
244 {
245         SCRIPTAPI_PRECHECKHEADER
246
247         //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
248
249         int error_handler = PUSH_ERROR_HANDLER(L);
250
251         // Get core.luaentities[id]
252         luaentity_get(L,id);
253         int object = lua_gettop(L);
254         // State: object is at top of stack
255         // Get function
256         lua_getfield(L, -1, "on_punch");
257         if (lua_isnil(L, -1)) {
258                 lua_pop(L, 2); // Pop on_punch and entity
259                 return false;
260         }
261         luaL_checktype(L, -1, LUA_TFUNCTION);
262         lua_pushvalue(L, object);  // self
263         objectrefGetOrCreate(L, puncher);  // Clicker reference
264         lua_pushnumber(L, time_from_last_punch);
265         push_tool_capabilities(L, *toolcap);
266         push_v3f(L, dir);
267         lua_pushnumber(L, damage);
268
269         setOriginFromTable(object);
270         PCALL_RES(lua_pcall(L, 6, 1, error_handler));
271
272         bool retval = readParam<bool>(L, -1);
273         lua_pop(L, 2); // Pop object and error handler
274         return retval;
275 }
276
277 // Calls entity[field](ObjectRef self, ObjectRef sao)
278 bool ScriptApiEntity::luaentity_run_simple_callback(u16 id,
279         ServerActiveObject *sao, const char *field)
280 {
281         SCRIPTAPI_PRECHECKHEADER
282
283         int error_handler = PUSH_ERROR_HANDLER(L);
284
285         // Get core.luaentities[id]
286         luaentity_get(L, id);
287         int object = lua_gettop(L);
288         // State: object is at top of stack
289         // Get function
290         lua_getfield(L, -1, field);
291         if (lua_isnil(L, -1)) {
292                 lua_pop(L, 2); // Pop callback field and entity
293                 return false;
294         }
295         luaL_checktype(L, -1, LUA_TFUNCTION);
296         lua_pushvalue(L, object);  // self
297         objectrefGetOrCreate(L, sao);  // killer reference
298
299         setOriginFromTable(object);
300         PCALL_RES(lua_pcall(L, 2, 1, error_handler));
301
302         bool retval = readParam<bool>(L, -1);
303         lua_pop(L, 2); // Pop object and error handler
304         return retval;
305 }
306
307 bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
308 {
309         return luaentity_run_simple_callback(id, killer, "on_death");
310 }
311
312 // Calls entity:on_rightclick(ObjectRef clicker)
313 void ScriptApiEntity::luaentity_Rightclick(u16 id, ServerActiveObject *clicker)
314 {
315         luaentity_run_simple_callback(id, clicker, "on_rightclick");
316 }
317
318 void ScriptApiEntity::luaentity_on_attach_child(u16 id, ServerActiveObject *child)
319 {
320         luaentity_run_simple_callback(id, child, "on_attach_child");
321 }
322
323 void ScriptApiEntity::luaentity_on_detach_child(u16 id, ServerActiveObject *child)
324 {
325         luaentity_run_simple_callback(id, child, "on_detach_child");
326 }
327
328 void ScriptApiEntity::luaentity_on_detach(u16 id, ServerActiveObject *parent)
329 {
330         luaentity_run_simple_callback(id, parent, "on_detach");
331 }