]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_object.cpp
Biomes: Add 'min_pos'/'max_pos' xyz biome limits
[minetest.git] / src / script / lua_api / l_object.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 "lua_api/l_object.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_inventory.h"
23 #include "lua_api/l_item.h"
24 #include "common/c_converter.h"
25 #include "common/c_content.h"
26 #include "log.h"
27 #include "tool.h"
28 #include "serverobject.h"
29 #include "content_sao.h"
30 #include "remoteplayer.h"
31 #include "server.h"
32 #include "hud.h"
33 #include "scripting_server.h"
34
35 /*
36         ObjectRef
37 */
38
39
40 ObjectRef* ObjectRef::checkobject(lua_State *L, int narg)
41 {
42         luaL_checktype(L, narg, LUA_TUSERDATA);
43         void *ud = luaL_checkudata(L, narg, className);
44         if (!ud) luaL_typerror(L, narg, className);
45         return *(ObjectRef**)ud;  // unbox pointer
46 }
47
48 ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
49 {
50         ServerActiveObject *co = ref->m_object;
51         return co;
52 }
53
54 LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
55 {
56         ServerActiveObject *obj = getobject(ref);
57         if (obj == NULL)
58                 return NULL;
59         if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
60                 return NULL;
61         return (LuaEntitySAO*)obj;
62 }
63
64 PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
65 {
66         ServerActiveObject *obj = getobject(ref);
67         if (obj == NULL)
68                 return NULL;
69         if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
70                 return NULL;
71         return (PlayerSAO*)obj;
72 }
73
74 RemotePlayer *ObjectRef::getplayer(ObjectRef *ref)
75 {
76         PlayerSAO *playersao = getplayersao(ref);
77         if (playersao == NULL)
78                 return NULL;
79         return playersao->getPlayer();
80 }
81
82 // Exported functions
83
84 // garbage collector
85 int ObjectRef::gc_object(lua_State *L) {
86         ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1));
87         //infostream<<"ObjectRef::gc_object: o="<<o<<std::endl;
88         delete o;
89         return 0;
90 }
91
92 // remove(self)
93 int ObjectRef::l_remove(lua_State *L)
94 {
95         GET_ENV_PTR;
96
97         ObjectRef *ref = checkobject(L, 1);
98         ServerActiveObject *co = getobject(ref);
99         if (co == NULL)
100                 return 0;
101         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
102                 return 0;
103
104         const std::unordered_set<int> &child_ids = co->getAttachmentChildIds();
105         for (int child_id : child_ids) {
106                 // Child can be NULL if it was deleted earlier
107                 if (ServerActiveObject *child = env->getActiveObject(child_id))
108                         child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
109         }
110
111         verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl;
112         co->m_pending_removal = true;
113         return 0;
114 }
115
116 // get_pos(self)
117 // returns: {x=num, y=num, z=num}
118 int ObjectRef::l_get_pos(lua_State *L)
119 {
120         NO_MAP_LOCK_REQUIRED;
121         ObjectRef *ref = checkobject(L, 1);
122         ServerActiveObject *co = getobject(ref);
123         if (co == NULL) return 0;
124         v3f pos = co->getBasePosition() / BS;
125         lua_newtable(L);
126         lua_pushnumber(L, pos.X);
127         lua_setfield(L, -2, "x");
128         lua_pushnumber(L, pos.Y);
129         lua_setfield(L, -2, "y");
130         lua_pushnumber(L, pos.Z);
131         lua_setfield(L, -2, "z");
132         return 1;
133 }
134
135 // set_pos(self, pos)
136 int ObjectRef::l_set_pos(lua_State *L)
137 {
138         NO_MAP_LOCK_REQUIRED;
139         ObjectRef *ref = checkobject(L, 1);
140         //LuaEntitySAO *co = getluaobject(ref);
141         ServerActiveObject *co = getobject(ref);
142         if (co == NULL) return 0;
143         // pos
144         v3f pos = checkFloatPos(L, 2);
145         // Do it
146         co->setPos(pos);
147         return 0;
148 }
149
150 // move_to(self, pos, continuous=false)
151 int ObjectRef::l_move_to(lua_State *L)
152 {
153         NO_MAP_LOCK_REQUIRED;
154         ObjectRef *ref = checkobject(L, 1);
155         //LuaEntitySAO *co = getluaobject(ref);
156         ServerActiveObject *co = getobject(ref);
157         if (co == NULL) return 0;
158         // pos
159         v3f pos = checkFloatPos(L, 2);
160         // continuous
161         bool continuous = lua_toboolean(L, 3);
162         // Do it
163         co->moveTo(pos, continuous);
164         return 0;
165 }
166
167 // punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
168 int ObjectRef::l_punch(lua_State *L)
169 {
170         NO_MAP_LOCK_REQUIRED;
171         ObjectRef *ref = checkobject(L, 1);
172         ObjectRef *puncher_ref = checkobject(L, 2);
173         ServerActiveObject *co = getobject(ref);
174         ServerActiveObject *puncher = getobject(puncher_ref);
175         if (co == NULL) return 0;
176         if (puncher == NULL) return 0;
177         v3f dir;
178         if (lua_type(L, 5) != LUA_TTABLE)
179                 dir = co->getBasePosition() - puncher->getBasePosition();
180         else
181                 dir = read_v3f(L, 5);
182         float time_from_last_punch = 1000000;
183         if (lua_isnumber(L, 3))
184                 time_from_last_punch = lua_tonumber(L, 3);
185         ToolCapabilities toolcap = read_tool_capabilities(L, 4);
186         dir.normalize();
187
188         s16 src_original_hp = co->getHP();
189         s16 dst_origin_hp = puncher->getHP();
190
191         // Do it
192         co->punch(dir, &toolcap, puncher, time_from_last_punch);
193
194         // If the punched is a player, and its HP changed
195         if (src_original_hp != co->getHP() &&
196                         co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
197                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
198         }
199
200         // If the puncher is a player, and its HP changed
201         if (dst_origin_hp != puncher->getHP() &&
202                         puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
203                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher);
204         }
205         return 0;
206 }
207
208 // right_click(self, clicker); clicker = an another ObjectRef
209 int ObjectRef::l_right_click(lua_State *L)
210 {
211         NO_MAP_LOCK_REQUIRED;
212         ObjectRef *ref = checkobject(L, 1);
213         ObjectRef *ref2 = checkobject(L, 2);
214         ServerActiveObject *co = getobject(ref);
215         ServerActiveObject *co2 = getobject(ref2);
216         if (co == NULL) return 0;
217         if (co2 == NULL) return 0;
218         // Do it
219         co->rightClick(co2);
220         return 0;
221 }
222
223 // set_hp(self, hp)
224 // hp = number of hitpoints (2 * number of hearts)
225 // returns: nil
226 int ObjectRef::l_set_hp(lua_State *L)
227 {
228         NO_MAP_LOCK_REQUIRED;
229         ObjectRef *ref = checkobject(L, 1);
230         luaL_checknumber(L, 2);
231         ServerActiveObject *co = getobject(ref);
232         if (co == NULL) return 0;
233         int hp = lua_tonumber(L, 2);
234         /*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
235                         <<" hp="<<hp<<std::endl;*/
236         // Do it
237         co->setHP(hp);
238         if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
239                 getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
240
241         // Return
242         return 0;
243 }
244
245 // get_hp(self)
246 // returns: number of hitpoints (2 * number of hearts)
247 // 0 if not applicable to this type of object
248 int ObjectRef::l_get_hp(lua_State *L)
249 {
250         NO_MAP_LOCK_REQUIRED;
251         ObjectRef *ref = checkobject(L, 1);
252         ServerActiveObject *co = getobject(ref);
253         if (co == NULL) {
254                 // Default hp is 1
255                 lua_pushnumber(L, 1);
256                 return 1;
257         }
258         int hp = co->getHP();
259         /*infostream<<"ObjectRef::l_get_hp(): id="<<co->getId()
260                         <<" hp="<<hp<<std::endl;*/
261         // Return
262         lua_pushnumber(L, hp);
263         return 1;
264 }
265
266 // get_inventory(self)
267 int ObjectRef::l_get_inventory(lua_State *L)
268 {
269         NO_MAP_LOCK_REQUIRED;
270         ObjectRef *ref = checkobject(L, 1);
271         ServerActiveObject *co = getobject(ref);
272         if (co == NULL) return 0;
273         // Do it
274         InventoryLocation loc = co->getInventoryLocation();
275         if (getServer(L)->getInventory(loc) != NULL)
276                 InvRef::create(L, loc);
277         else
278                 lua_pushnil(L); // An object may have no inventory (nil)
279         return 1;
280 }
281
282 // get_wield_list(self)
283 int ObjectRef::l_get_wield_list(lua_State *L)
284 {
285         NO_MAP_LOCK_REQUIRED;
286         ObjectRef *ref = checkobject(L, 1);
287         ServerActiveObject *co = getobject(ref);
288         if (co == NULL) return 0;
289         // Do it
290         lua_pushstring(L, co->getWieldList().c_str());
291         return 1;
292 }
293
294 // get_wield_index(self)
295 int ObjectRef::l_get_wield_index(lua_State *L)
296 {
297         NO_MAP_LOCK_REQUIRED;
298         ObjectRef *ref = checkobject(L, 1);
299         ServerActiveObject *co = getobject(ref);
300         if (co == NULL) return 0;
301         // Do it
302         lua_pushinteger(L, co->getWieldIndex() + 1);
303         return 1;
304 }
305
306 // get_wielded_item(self)
307 int ObjectRef::l_get_wielded_item(lua_State *L)
308 {
309         NO_MAP_LOCK_REQUIRED;
310         ObjectRef *ref = checkobject(L, 1);
311         ServerActiveObject *co = getobject(ref);
312         if (co == NULL) {
313                 // Empty ItemStack
314                 LuaItemStack::create(L, ItemStack());
315                 return 1;
316         }
317         // Do it
318         LuaItemStack::create(L, co->getWieldedItem());
319         return 1;
320 }
321
322 // set_wielded_item(self, itemstack or itemstring or table or nil)
323 int ObjectRef::l_set_wielded_item(lua_State *L)
324 {
325         NO_MAP_LOCK_REQUIRED;
326         ObjectRef *ref = checkobject(L, 1);
327         ServerActiveObject *co = getobject(ref);
328         if (co == NULL) return 0;
329         // Do it
330         ItemStack item = read_item(L, 2, getServer(L)->idef());
331         bool success = co->setWieldedItem(item);
332         if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
333                 getServer(L)->SendInventory(((PlayerSAO*)co));
334         }
335         lua_pushboolean(L, success);
336         return 1;
337 }
338
339 // set_armor_groups(self, groups)
340 int ObjectRef::l_set_armor_groups(lua_State *L)
341 {
342         NO_MAP_LOCK_REQUIRED;
343         ObjectRef *ref = checkobject(L, 1);
344         ServerActiveObject *co = getobject(ref);
345         if (co == NULL) return 0;
346         // Do it
347         ItemGroupList groups;
348         read_groups(L, 2, groups);
349         co->setArmorGroups(groups);
350         return 0;
351 }
352
353 // get_armor_groups(self)
354 int ObjectRef::l_get_armor_groups(lua_State *L)
355 {
356         NO_MAP_LOCK_REQUIRED;
357         ObjectRef *ref = checkobject(L, 1);
358         ServerActiveObject *co = getobject(ref);
359         if (co == NULL)
360                 return 0;
361         // Do it
362         push_groups(L, co->getArmorGroups());
363         return 1;
364 }
365
366 // set_physics_override(self, physics_override_speed, physics_override_jump,
367 //                      physics_override_gravity, sneak, sneak_glitch, new_move)
368 int ObjectRef::l_set_physics_override(lua_State *L)
369 {
370         NO_MAP_LOCK_REQUIRED;
371         ObjectRef *ref = checkobject(L, 1);
372         PlayerSAO *co = (PlayerSAO *) getobject(ref);
373         if (co == NULL) return 0;
374         // Do it
375         if (lua_istable(L, 2)) {
376                 co->m_physics_override_speed = getfloatfield_default(
377                                 L, 2, "speed", co->m_physics_override_speed);
378                 co->m_physics_override_jump = getfloatfield_default(
379                                 L, 2, "jump", co->m_physics_override_jump);
380                 co->m_physics_override_gravity = getfloatfield_default(
381                                 L, 2, "gravity", co->m_physics_override_gravity);
382                 co->m_physics_override_sneak = getboolfield_default(
383                                 L, 2, "sneak", co->m_physics_override_sneak);
384                 co->m_physics_override_sneak_glitch = getboolfield_default(
385                                 L, 2, "sneak_glitch", co->m_physics_override_sneak_glitch);
386                 co->m_physics_override_new_move = getboolfield_default(
387                                 L, 2, "new_move", co->m_physics_override_new_move);
388                 co->m_physics_override_sent = false;
389         } else {
390                 // old, non-table format
391                 if (!lua_isnil(L, 2)) {
392                         co->m_physics_override_speed = lua_tonumber(L, 2);
393                         co->m_physics_override_sent = false;
394                 }
395                 if (!lua_isnil(L, 3)) {
396                         co->m_physics_override_jump = lua_tonumber(L, 3);
397                         co->m_physics_override_sent = false;
398                 }
399                 if (!lua_isnil(L, 4)) {
400                         co->m_physics_override_gravity = lua_tonumber(L, 4);
401                         co->m_physics_override_sent = false;
402                 }
403         }
404         return 0;
405 }
406
407 // get_physics_override(self)
408 int ObjectRef::l_get_physics_override(lua_State *L)
409 {
410         NO_MAP_LOCK_REQUIRED;
411         ObjectRef *ref = checkobject(L, 1);
412         PlayerSAO *co = (PlayerSAO *)getobject(ref);
413         if (co == NULL)
414                 return 0;
415         // Do it
416         lua_newtable(L);
417         lua_pushnumber(L, co->m_physics_override_speed);
418         lua_setfield(L, -2, "speed");
419         lua_pushnumber(L, co->m_physics_override_jump);
420         lua_setfield(L, -2, "jump");
421         lua_pushnumber(L, co->m_physics_override_gravity);
422         lua_setfield(L, -2, "gravity");
423         lua_pushboolean(L, co->m_physics_override_sneak);
424         lua_setfield(L, -2, "sneak");
425         lua_pushboolean(L, co->m_physics_override_sneak_glitch);
426         lua_setfield(L, -2, "sneak_glitch");
427         lua_pushboolean(L, co->m_physics_override_new_move);
428         lua_setfield(L, -2, "new_move");
429         return 1;
430 }
431
432 // set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
433 int ObjectRef::l_set_animation(lua_State *L)
434 {
435         NO_MAP_LOCK_REQUIRED;
436         ObjectRef *ref = checkobject(L, 1);
437         ServerActiveObject *co = getobject(ref);
438         if (co == NULL) return 0;
439         // Do it
440         v2f frames = v2f(1, 1);
441         if (!lua_isnil(L, 2))
442                 frames = read_v2f(L, 2);
443         float frame_speed = 15;
444         if (!lua_isnil(L, 3))
445                 frame_speed = lua_tonumber(L, 3);
446         float frame_blend = 0;
447         if (!lua_isnil(L, 4))
448                 frame_blend = lua_tonumber(L, 4);
449         bool frame_loop = true;
450         if (lua_isboolean(L, 5))
451                 frame_loop = lua_toboolean(L, 5);
452         co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
453         return 0;
454 }
455
456 // get_animation(self)
457 int ObjectRef::l_get_animation(lua_State *L)
458 {
459         NO_MAP_LOCK_REQUIRED;
460         ObjectRef *ref = checkobject(L, 1);
461         ServerActiveObject *co = getobject(ref);
462         if (co == NULL)
463                 return 0;
464         // Do it
465         v2f frames = v2f(1,1);
466         float frame_speed = 15;
467         float frame_blend = 0;
468         bool frame_loop = true;
469         co->getAnimation(&frames, &frame_speed, &frame_blend, &frame_loop);
470
471         push_v2f(L, frames);
472         lua_pushnumber(L, frame_speed);
473         lua_pushnumber(L, frame_blend);
474         lua_pushboolean(L, frame_loop);
475         return 4;
476 }
477
478 // set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
479 int ObjectRef::l_set_local_animation(lua_State *L)
480 {
481         NO_MAP_LOCK_REQUIRED;
482         ObjectRef *ref = checkobject(L, 1);
483         RemotePlayer *player = getplayer(ref);
484         if (player == NULL)
485                 return 0;
486         // Do it
487         v2s32 frames[4];
488         for (int i=0;i<4;i++) {
489                 if (!lua_isnil(L, 2+1))
490                         frames[i] = read_v2s32(L, 2+i);
491         }
492         float frame_speed = 30;
493         if (!lua_isnil(L, 6))
494                 frame_speed = lua_tonumber(L, 6);
495
496         getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed);
497         lua_pushboolean(L, true);
498         return 1;
499 }
500
501 // get_local_animation(self)
502 int ObjectRef::l_get_local_animation(lua_State *L)
503 {
504         NO_MAP_LOCK_REQUIRED
505         ObjectRef *ref = checkobject(L, 1);
506         RemotePlayer *player = getplayer(ref);
507         if (player == NULL)
508                 return 0;
509
510         v2s32 frames[4];
511         float frame_speed;
512         player->getLocalAnimations(frames, &frame_speed);
513
514         for (const v2s32 &frame : frames) {
515                 push_v2s32(L, frame);
516         }
517
518         lua_pushnumber(L, frame_speed);
519         return 5;
520 }
521
522 // set_eye_offset(self, v3f first pv, v3f third pv)
523 int ObjectRef::l_set_eye_offset(lua_State *L)
524 {
525         NO_MAP_LOCK_REQUIRED;
526         ObjectRef *ref = checkobject(L, 1);
527         RemotePlayer *player = getplayer(ref);
528         if (player == NULL)
529                 return 0;
530         // Do it
531         v3f offset_first = v3f(0, 0, 0);
532         v3f offset_third = v3f(0, 0, 0);
533
534         if (!lua_isnil(L, 2))
535                 offset_first = read_v3f(L, 2);
536         if (!lua_isnil(L, 3))
537                 offset_third = read_v3f(L, 3);
538
539         // Prevent abuse of offset values (keep player always visible)
540         offset_third.X = rangelim(offset_third.X,-10,10);
541         offset_third.Z = rangelim(offset_third.Z,-5,5);
542         /* TODO: if possible: improve the camera colision detetion to allow Y <= -1.5) */
543         offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS
544
545         getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third);
546         lua_pushboolean(L, true);
547         return 1;
548 }
549
550 // get_eye_offset(self)
551 int ObjectRef::l_get_eye_offset(lua_State *L)
552 {
553         NO_MAP_LOCK_REQUIRED;
554         ObjectRef *ref = checkobject(L, 1);
555         RemotePlayer *player = getplayer(ref);
556         if (player == NULL)
557                 return 0;
558         // Do it
559         push_v3f(L, player->eye_offset_first);
560         push_v3f(L, player->eye_offset_third);
561         return 2;
562 }
563
564 // set_animation_frame_speed(self, frame_speed)
565 int ObjectRef::l_set_animation_frame_speed(lua_State *L)
566 {
567         NO_MAP_LOCK_REQUIRED;
568         ObjectRef *ref = checkobject(L, 1);
569         ServerActiveObject *co = getobject(ref);
570         if (co == NULL)
571                 return 0;
572
573         // Do it
574         if (!lua_isnil(L, 2)) {
575                 float frame_speed = lua_tonumber(L, 2);
576                 co->setAnimationSpeed(frame_speed);
577                 lua_pushboolean(L, true);
578         } else {
579                 lua_pushboolean(L, false);
580         }
581         return 1;
582 }
583
584 // set_bone_position(self, std::string bone, v3f position, v3f rotation)
585 int ObjectRef::l_set_bone_position(lua_State *L)
586 {
587         NO_MAP_LOCK_REQUIRED;
588         ObjectRef *ref = checkobject(L, 1);
589         ServerActiveObject *co = getobject(ref);
590         if (co == NULL) return 0;
591         // Do it
592         std::string bone;
593         if (!lua_isnil(L, 2))
594                 bone = lua_tostring(L, 2);
595         v3f position = v3f(0, 0, 0);
596         if (!lua_isnil(L, 3))
597                 position = check_v3f(L, 3);
598         v3f rotation = v3f(0, 0, 0);
599         if (!lua_isnil(L, 4))
600                 rotation = check_v3f(L, 4);
601         co->setBonePosition(bone, position, rotation);
602         return 0;
603 }
604
605 // get_bone_position(self, bone)
606 int ObjectRef::l_get_bone_position(lua_State *L)
607 {
608         NO_MAP_LOCK_REQUIRED;
609         ObjectRef *ref = checkobject(L, 1);
610         ServerActiveObject *co = getobject(ref);
611         if (co == NULL)
612                 return 0;
613         // Do it
614         std::string bone;
615         if (!lua_isnil(L, 2))
616                 bone = lua_tostring(L, 2);
617
618         v3f position = v3f(0, 0, 0);
619         v3f rotation = v3f(0, 0, 0);
620         co->getBonePosition(bone, &position, &rotation);
621
622         push_v3f(L, position);
623         push_v3f(L, rotation);
624         return 2;
625 }
626
627 // set_attach(self, parent, bone, position, rotation)
628 int ObjectRef::l_set_attach(lua_State *L)
629 {
630         GET_ENV_PTR;
631
632         ObjectRef *ref = checkobject(L, 1);
633         ObjectRef *parent_ref = checkobject(L, 2);
634         ServerActiveObject *co = getobject(ref);
635         ServerActiveObject *parent = getobject(parent_ref);
636         if (co == NULL)
637                 return 0;
638         if (parent == NULL)
639                 return 0;
640         // Do it
641         int parent_id = 0;
642         std::string bone;
643         v3f position = v3f(0, 0, 0);
644         v3f rotation = v3f(0, 0, 0);
645         co->getAttachment(&parent_id, &bone, &position, &rotation);
646         if (parent_id) {
647                 ServerActiveObject *old_parent = env->getActiveObject(parent_id);
648                 old_parent->removeAttachmentChild(co->getId());
649         }
650
651         bone = "";
652         if (!lua_isnil(L, 3))
653                 bone = lua_tostring(L, 3);
654         position = v3f(0, 0, 0);
655         if (!lua_isnil(L, 4))
656                 position = read_v3f(L, 4);
657         rotation = v3f(0, 0, 0);
658         if (!lua_isnil(L, 5))
659                 rotation = read_v3f(L, 5);
660         co->setAttachment(parent->getId(), bone, position, rotation);
661         parent->addAttachmentChild(co->getId());
662         return 0;
663 }
664
665 // get_attach(self)
666 int ObjectRef::l_get_attach(lua_State *L)
667 {
668         GET_ENV_PTR;
669
670         ObjectRef *ref = checkobject(L, 1);
671         ServerActiveObject *co = getobject(ref);
672         if (co == NULL)
673                 return 0;
674
675         // Do it
676         int parent_id = 0;
677         std::string bone;
678         v3f position = v3f(0, 0, 0);
679         v3f rotation = v3f(0, 0, 0);
680         co->getAttachment(&parent_id, &bone, &position, &rotation);
681         if (!parent_id)
682                 return 0;
683         ServerActiveObject *parent = env->getActiveObject(parent_id);
684
685         getScriptApiBase(L)->objectrefGetOrCreate(L, parent);
686         lua_pushlstring(L, bone.c_str(), bone.size());
687         push_v3f(L, position);
688         push_v3f(L, rotation);
689         return 4;
690 }
691
692 // set_detach(self)
693 int ObjectRef::l_set_detach(lua_State *L)
694 {
695         GET_ENV_PTR;
696
697         ObjectRef *ref = checkobject(L, 1);
698         ServerActiveObject *co = getobject(ref);
699         if (co == NULL)
700                 return 0;
701
702         int parent_id = 0;
703         std::string bone;
704         v3f position;
705         v3f rotation;
706         co->getAttachment(&parent_id, &bone, &position, &rotation);
707         ServerActiveObject *parent = NULL;
708         if (parent_id) {
709                 parent = env->getActiveObject(parent_id);
710                 co->setAttachment(0, "", position, rotation);
711         } else {
712                 co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
713         }
714         // Do it
715         if (parent != NULL)
716                 parent->removeAttachmentChild(co->getId());
717         return 0;
718 }
719
720 // set_properties(self, properties)
721 int ObjectRef::l_set_properties(lua_State *L)
722 {
723         NO_MAP_LOCK_REQUIRED;
724         ObjectRef *ref = checkobject(L, 1);
725         ServerActiveObject *co = getobject(ref);
726         if (co == NULL) return 0;
727         ObjectProperties *prop = co->accessObjectProperties();
728         if (!prop)
729                 return 0;
730         read_object_properties(L, 2, prop, getServer(L)->idef());
731         if (prop->hp_max < co->getHP()) {
732                 co->setHP(prop->hp_max);
733                 if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
734                         getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
735         }
736         co->notifyObjectPropertiesModified();
737         return 0;
738 }
739
740 // get_properties(self)
741 int ObjectRef::l_get_properties(lua_State *L)
742 {
743         NO_MAP_LOCK_REQUIRED;
744         ObjectRef *ref = checkobject(L, 1);
745         ServerActiveObject *co = getobject(ref);
746         if (co == NULL)
747                 return 0;
748         ObjectProperties *prop = co->accessObjectProperties();
749         if (!prop)
750                 return 0;
751         push_object_properties(L, prop);
752         return 1;
753 }
754
755 // is_player(self)
756 int ObjectRef::l_is_player(lua_State *L)
757 {
758         NO_MAP_LOCK_REQUIRED;
759         ObjectRef *ref = checkobject(L, 1);
760         RemotePlayer *player = getplayer(ref);
761         lua_pushboolean(L, (player != NULL));
762         return 1;
763 }
764
765 // set_nametag_attributes(self, attributes)
766 int ObjectRef::l_set_nametag_attributes(lua_State *L)
767 {
768         NO_MAP_LOCK_REQUIRED;
769         ObjectRef *ref = checkobject(L, 1);
770         ServerActiveObject *co = getobject(ref);
771
772         if (co == NULL)
773                 return 0;
774         ObjectProperties *prop = co->accessObjectProperties();
775         if (!prop)
776                 return 0;
777
778         lua_getfield(L, 2, "color");
779         if (!lua_isnil(L, -1)) {
780                 video::SColor color = prop->nametag_color;
781                 read_color(L, -1, &color);
782                 prop->nametag_color = color;
783         }
784         lua_pop(L, 1);
785
786         std::string nametag = getstringfield_default(L, 2, "text", "");
787         prop->nametag = nametag;
788
789         co->notifyObjectPropertiesModified();
790         lua_pushboolean(L, true);
791         return 1;
792 }
793
794 // get_nametag_attributes(self)
795 int ObjectRef::l_get_nametag_attributes(lua_State *L)
796 {
797         NO_MAP_LOCK_REQUIRED;
798         ObjectRef *ref = checkobject(L, 1);
799         ServerActiveObject *co = getobject(ref);
800
801         if (co == NULL)
802                 return 0;
803         ObjectProperties *prop = co->accessObjectProperties();
804         if (!prop)
805                 return 0;
806
807         video::SColor color = prop->nametag_color;
808
809         lua_newtable(L);
810         push_ARGB8(L, color);
811         lua_setfield(L, -2, "color");
812         lua_pushstring(L, prop->nametag.c_str());
813         lua_setfield(L, -2, "text");
814         return 1;
815 }
816
817 /* LuaEntitySAO-only */
818
819 // set_velocity(self, {x=num, y=num, z=num})
820 int ObjectRef::l_set_velocity(lua_State *L)
821 {
822         NO_MAP_LOCK_REQUIRED;
823         ObjectRef *ref = checkobject(L, 1);
824         LuaEntitySAO *co = getluaobject(ref);
825         if (co == NULL) return 0;
826         v3f pos = checkFloatPos(L, 2);
827         // Do it
828         co->setVelocity(pos);
829         return 0;
830 }
831
832 // get_velocity(self)
833 int ObjectRef::l_get_velocity(lua_State *L)
834 {
835         NO_MAP_LOCK_REQUIRED;
836         ObjectRef *ref = checkobject(L, 1);
837         LuaEntitySAO *co = getluaobject(ref);
838         if (co == NULL) return 0;
839         // Do it
840         v3f v = co->getVelocity();
841         pushFloatPos(L, v);
842         return 1;
843 }
844
845 // set_acceleration(self, {x=num, y=num, z=num})
846 int ObjectRef::l_set_acceleration(lua_State *L)
847 {
848         NO_MAP_LOCK_REQUIRED;
849         ObjectRef *ref = checkobject(L, 1);
850         LuaEntitySAO *co = getluaobject(ref);
851         if (co == NULL) return 0;
852         // pos
853         v3f pos = checkFloatPos(L, 2);
854         // Do it
855         co->setAcceleration(pos);
856         return 0;
857 }
858
859 // get_acceleration(self)
860 int ObjectRef::l_get_acceleration(lua_State *L)
861 {
862         NO_MAP_LOCK_REQUIRED;
863         ObjectRef *ref = checkobject(L, 1);
864         LuaEntitySAO *co = getluaobject(ref);
865         if (co == NULL) return 0;
866         // Do it
867         v3f v = co->getAcceleration();
868         pushFloatPos(L, v);
869         return 1;
870 }
871
872 // set_yaw(self, radians)
873 int ObjectRef::l_set_yaw(lua_State *L)
874 {
875         NO_MAP_LOCK_REQUIRED;
876         ObjectRef *ref = checkobject(L, 1);
877         LuaEntitySAO *co = getluaobject(ref);
878         if (co == NULL) return 0;
879         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
880         // Do it
881         co->setYaw(yaw);
882         return 0;
883 }
884
885 // get_yaw(self)
886 int ObjectRef::l_get_yaw(lua_State *L)
887 {
888         NO_MAP_LOCK_REQUIRED;
889         ObjectRef *ref = checkobject(L, 1);
890         LuaEntitySAO *co = getluaobject(ref);
891         if (co == NULL) return 0;
892         // Do it
893         float yaw = co->getYaw() * core::DEGTORAD;
894         lua_pushnumber(L, yaw);
895         return 1;
896 }
897
898 // set_texture_mod(self, mod)
899 int ObjectRef::l_set_texture_mod(lua_State *L)
900 {
901         NO_MAP_LOCK_REQUIRED;
902         ObjectRef *ref = checkobject(L, 1);
903         LuaEntitySAO *co = getluaobject(ref);
904         if (co == NULL) return 0;
905         // Do it
906         std::string mod = luaL_checkstring(L, 2);
907         co->setTextureMod(mod);
908         return 0;
909 }
910
911 // get_texture_mod(self)
912 int ObjectRef::l_get_texture_mod(lua_State *L)
913 {
914         NO_MAP_LOCK_REQUIRED;
915         ObjectRef *ref = checkobject(L, 1);
916         LuaEntitySAO *co = getluaobject(ref);
917         if (co == NULL) return 0;
918         // Do it
919         std::string mod = co->getTextureMod();
920         lua_pushstring(L, mod.c_str());
921         return 1;
922 }
923
924 // set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
925 //           select_horiz_by_yawpitch=false)
926 int ObjectRef::l_set_sprite(lua_State *L)
927 {
928         NO_MAP_LOCK_REQUIRED;
929         ObjectRef *ref = checkobject(L, 1);
930         LuaEntitySAO *co = getluaobject(ref);
931         if (co == NULL) return 0;
932         // Do it
933         v2s16 p(0,0);
934         if (!lua_isnil(L, 2))
935                 p = read_v2s16(L, 2);
936         int num_frames = 1;
937         if (!lua_isnil(L, 3))
938                 num_frames = lua_tonumber(L, 3);
939         float framelength = 0.2;
940         if (!lua_isnil(L, 4))
941                 framelength = lua_tonumber(L, 4);
942         bool select_horiz_by_yawpitch = false;
943         if (!lua_isnil(L, 5))
944                 select_horiz_by_yawpitch = lua_toboolean(L, 5);
945         co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
946         return 0;
947 }
948
949 // DEPRECATED
950 // get_entity_name(self)
951 int ObjectRef::l_get_entity_name(lua_State *L)
952 {
953         NO_MAP_LOCK_REQUIRED;
954         ObjectRef *ref = checkobject(L, 1);
955         LuaEntitySAO *co = getluaobject(ref);
956         log_deprecated(L,"Deprecated call to \"get_entity_name");
957         if (co == NULL) return 0;
958         // Do it
959         std::string name = co->getName();
960         lua_pushstring(L, name.c_str());
961         return 1;
962 }
963
964 // get_luaentity(self)
965 int ObjectRef::l_get_luaentity(lua_State *L)
966 {
967         NO_MAP_LOCK_REQUIRED;
968         ObjectRef *ref = checkobject(L, 1);
969         LuaEntitySAO *co = getluaobject(ref);
970         if (co == NULL) return 0;
971         // Do it
972         luaentity_get(L, co->getId());
973         return 1;
974 }
975
976 /* Player-only */
977
978 // is_player_connected(self)
979 int ObjectRef::l_is_player_connected(lua_State *L)
980 {
981         NO_MAP_LOCK_REQUIRED;
982         ObjectRef *ref = checkobject(L, 1);
983         RemotePlayer *player = getplayer(ref);
984         lua_pushboolean(L, (player != NULL && player->getPeerId() != PEER_ID_INEXISTENT));
985         return 1;
986 }
987
988 // get_player_name(self)
989 int ObjectRef::l_get_player_name(lua_State *L)
990 {
991         NO_MAP_LOCK_REQUIRED;
992         ObjectRef *ref = checkobject(L, 1);
993         RemotePlayer *player = getplayer(ref);
994         if (player == NULL) {
995                 lua_pushlstring(L, "", 0);
996                 return 1;
997         }
998         // Do it
999         lua_pushstring(L, player->getName());
1000         return 1;
1001 }
1002
1003 // get_player_velocity(self)
1004 int ObjectRef::l_get_player_velocity(lua_State *L)
1005 {
1006         NO_MAP_LOCK_REQUIRED;
1007         ObjectRef *ref = checkobject(L, 1);
1008         RemotePlayer *player = getplayer(ref);
1009         if (player == NULL) {
1010                 lua_pushnil(L);
1011                 return 1;
1012         }
1013         // Do it
1014         push_v3f(L, player->getSpeed() / BS);
1015         return 1;
1016 }
1017
1018 // get_look_dir(self)
1019 int ObjectRef::l_get_look_dir(lua_State *L)
1020 {
1021         NO_MAP_LOCK_REQUIRED;
1022         ObjectRef *ref = checkobject(L, 1);
1023         PlayerSAO* co = getplayersao(ref);
1024         if (co == NULL) return 0;
1025         // Do it
1026         float pitch = co->getRadPitchDep();
1027         float yaw = co->getRadYawDep();
1028         v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
1029         push_v3f(L, v);
1030         return 1;
1031 }
1032
1033 // DEPRECATED
1034 // get_look_pitch(self)
1035 int ObjectRef::l_get_look_pitch(lua_State *L)
1036 {
1037         NO_MAP_LOCK_REQUIRED;
1038
1039         log_deprecated(L,
1040                 "Deprecated call to get_look_pitch, use get_look_vertical instead");
1041
1042         ObjectRef *ref = checkobject(L, 1);
1043         PlayerSAO* co = getplayersao(ref);
1044         if (co == NULL) return 0;
1045         // Do it
1046         lua_pushnumber(L, co->getRadPitchDep());
1047         return 1;
1048 }
1049
1050 // DEPRECATED
1051 // get_look_yaw(self)
1052 int ObjectRef::l_get_look_yaw(lua_State *L)
1053 {
1054         NO_MAP_LOCK_REQUIRED;
1055
1056         log_deprecated(L,
1057                 "Deprecated call to get_look_yaw, use get_look_horizontal instead");
1058
1059         ObjectRef *ref = checkobject(L, 1);
1060         PlayerSAO* co = getplayersao(ref);
1061         if (co == NULL) return 0;
1062         // Do it
1063         lua_pushnumber(L, co->getRadYawDep());
1064         return 1;
1065 }
1066
1067 // get_look_pitch2(self)
1068 int ObjectRef::l_get_look_vertical(lua_State *L)
1069 {
1070         NO_MAP_LOCK_REQUIRED;
1071         ObjectRef *ref = checkobject(L, 1);
1072         PlayerSAO* co = getplayersao(ref);
1073         if (co == NULL) return 0;
1074         // Do it
1075         lua_pushnumber(L, co->getRadPitch());
1076         return 1;
1077 }
1078
1079 // get_look_yaw2(self)
1080 int ObjectRef::l_get_look_horizontal(lua_State *L)
1081 {
1082         NO_MAP_LOCK_REQUIRED;
1083         ObjectRef *ref = checkobject(L, 1);
1084         PlayerSAO* co = getplayersao(ref);
1085         if (co == NULL) return 0;
1086         // Do it
1087         lua_pushnumber(L, co->getRadYaw());
1088         return 1;
1089 }
1090
1091 // set_look_vertical(self, radians)
1092 int ObjectRef::l_set_look_vertical(lua_State *L)
1093 {
1094         NO_MAP_LOCK_REQUIRED;
1095         ObjectRef *ref = checkobject(L, 1);
1096         PlayerSAO* co = getplayersao(ref);
1097         if (co == NULL) return 0;
1098         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1099         // Do it
1100         co->setPitchAndSend(pitch);
1101         return 1;
1102 }
1103
1104 // set_look_horizontal(self, radians)
1105 int ObjectRef::l_set_look_horizontal(lua_State *L)
1106 {
1107         NO_MAP_LOCK_REQUIRED;
1108         ObjectRef *ref = checkobject(L, 1);
1109         PlayerSAO* co = getplayersao(ref);
1110         if (co == NULL) return 0;
1111         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1112         // Do it
1113         co->setYawAndSend(yaw);
1114         return 1;
1115 }
1116
1117 // DEPRECATED
1118 // set_look_pitch(self, radians)
1119 int ObjectRef::l_set_look_pitch(lua_State *L)
1120 {
1121         NO_MAP_LOCK_REQUIRED;
1122
1123         log_deprecated(L,
1124                 "Deprecated call to set_look_pitch, use set_look_vertical instead.");
1125
1126         ObjectRef *ref = checkobject(L, 1);
1127         PlayerSAO* co = getplayersao(ref);
1128         if (co == NULL) return 0;
1129         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1130         // Do it
1131         co->setPitchAndSend(pitch);
1132         return 1;
1133 }
1134
1135 // DEPRECATED
1136 // set_look_yaw(self, radians)
1137 int ObjectRef::l_set_look_yaw(lua_State *L)
1138 {
1139         NO_MAP_LOCK_REQUIRED;
1140
1141         log_deprecated(L,
1142                 "Deprecated call to set_look_yaw, use set_look_horizontal instead.");
1143
1144         ObjectRef *ref = checkobject(L, 1);
1145         PlayerSAO* co = getplayersao(ref);
1146         if (co == NULL) return 0;
1147         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1148         // Do it
1149         co->setYawAndSend(yaw);
1150         return 1;
1151 }
1152
1153 // set_breath(self, breath)
1154 int ObjectRef::l_set_breath(lua_State *L)
1155 {
1156         NO_MAP_LOCK_REQUIRED;
1157         ObjectRef *ref = checkobject(L, 1);
1158         PlayerSAO* co = getplayersao(ref);
1159         if (co == NULL) return 0;
1160         u16 breath = luaL_checknumber(L, 2);
1161         co->setBreath(breath);
1162
1163         return 0;
1164 }
1165
1166 // get_breath(self)
1167 int ObjectRef::l_get_breath(lua_State *L)
1168 {
1169         NO_MAP_LOCK_REQUIRED;
1170         ObjectRef *ref = checkobject(L, 1);
1171         PlayerSAO* co = getplayersao(ref);
1172         if (co == NULL) return 0;
1173         // Do it
1174         u16 breath = co->getBreath();
1175         lua_pushinteger (L, breath);
1176         return 1;
1177 }
1178
1179 // set_attribute(self, attribute, value)
1180 int ObjectRef::l_set_attribute(lua_State *L)
1181 {
1182         ObjectRef *ref = checkobject(L, 1);
1183         PlayerSAO* co = getplayersao(ref);
1184         if (co == NULL) {
1185                 return 0;
1186         }
1187
1188         std::string attr = luaL_checkstring(L, 2);
1189         if (lua_isnil(L, 3)) {
1190                 co->removeExtendedAttribute(attr);
1191         } else {
1192                 std::string value = luaL_checkstring(L, 3);
1193                 co->setExtendedAttribute(attr, value);
1194         }
1195         return 1;
1196 }
1197
1198 // get_attribute(self, attribute)
1199 int ObjectRef::l_get_attribute(lua_State *L)
1200 {
1201         ObjectRef *ref = checkobject(L, 1);
1202         PlayerSAO* co = getplayersao(ref);
1203         if (co == NULL) {
1204                 return 0;
1205         }
1206
1207         std::string attr = luaL_checkstring(L, 2);
1208
1209         std::string value;
1210         if (co->getExtendedAttribute(attr, &value)) {
1211                 lua_pushstring(L, value.c_str());
1212                 return 1;
1213         }
1214
1215         return 0;
1216 }
1217
1218
1219 // set_inventory_formspec(self, formspec)
1220 int ObjectRef::l_set_inventory_formspec(lua_State *L)
1221 {
1222         NO_MAP_LOCK_REQUIRED;
1223         ObjectRef *ref = checkobject(L, 1);
1224         RemotePlayer *player = getplayer(ref);
1225         if (player == NULL) return 0;
1226         std::string formspec = luaL_checkstring(L, 2);
1227
1228         player->inventory_formspec = formspec;
1229         getServer(L)->reportInventoryFormspecModified(player->getName());
1230         lua_pushboolean(L, true);
1231         return 1;
1232 }
1233
1234 // get_inventory_formspec(self) -> formspec
1235 int ObjectRef::l_get_inventory_formspec(lua_State *L)
1236 {
1237         NO_MAP_LOCK_REQUIRED;
1238         ObjectRef *ref = checkobject(L, 1);
1239         RemotePlayer *player = getplayer(ref);
1240         if (player == NULL) return 0;
1241
1242         std::string formspec = player->inventory_formspec;
1243         lua_pushlstring(L, formspec.c_str(), formspec.size());
1244         return 1;
1245 }
1246
1247 // get_player_control(self)
1248 int ObjectRef::l_get_player_control(lua_State *L)
1249 {
1250         NO_MAP_LOCK_REQUIRED;
1251         ObjectRef *ref = checkobject(L, 1);
1252         RemotePlayer *player = getplayer(ref);
1253         if (player == NULL) {
1254                 lua_pushlstring(L, "", 0);
1255                 return 1;
1256         }
1257
1258         const PlayerControl &control = player->getPlayerControl();
1259         lua_newtable(L);
1260         lua_pushboolean(L, control.up);
1261         lua_setfield(L, -2, "up");
1262         lua_pushboolean(L, control.down);
1263         lua_setfield(L, -2, "down");
1264         lua_pushboolean(L, control.left);
1265         lua_setfield(L, -2, "left");
1266         lua_pushboolean(L, control.right);
1267         lua_setfield(L, -2, "right");
1268         lua_pushboolean(L, control.jump);
1269         lua_setfield(L, -2, "jump");
1270         lua_pushboolean(L, control.aux1);
1271         lua_setfield(L, -2, "aux1");
1272         lua_pushboolean(L, control.sneak);
1273         lua_setfield(L, -2, "sneak");
1274         lua_pushboolean(L, control.LMB);
1275         lua_setfield(L, -2, "LMB");
1276         lua_pushboolean(L, control.RMB);
1277         lua_setfield(L, -2, "RMB");
1278         return 1;
1279 }
1280
1281 // get_player_control_bits(self)
1282 int ObjectRef::l_get_player_control_bits(lua_State *L)
1283 {
1284         NO_MAP_LOCK_REQUIRED;
1285         ObjectRef *ref = checkobject(L, 1);
1286         RemotePlayer *player = getplayer(ref);
1287         if (player == NULL) {
1288                 lua_pushlstring(L, "", 0);
1289                 return 1;
1290         }
1291         // Do it
1292         lua_pushnumber(L, player->keyPressed);
1293         return 1;
1294 }
1295
1296 // hud_add(self, form)
1297 int ObjectRef::l_hud_add(lua_State *L)
1298 {
1299         NO_MAP_LOCK_REQUIRED;
1300         ObjectRef *ref = checkobject(L, 1);
1301         RemotePlayer *player = getplayer(ref);
1302         if (player == NULL)
1303                 return 0;
1304
1305         HudElement *elem = new HudElement;
1306         read_hud_element(L, elem);
1307
1308         u32 id = getServer(L)->hudAdd(player, elem);
1309         if (id == U32_MAX) {
1310                 delete elem;
1311                 return 0;
1312         }
1313
1314         lua_pushnumber(L, id);
1315         return 1;
1316 }
1317
1318 // hud_remove(self, id)
1319 int ObjectRef::l_hud_remove(lua_State *L)
1320 {
1321         NO_MAP_LOCK_REQUIRED;
1322         ObjectRef *ref = checkobject(L, 1);
1323         RemotePlayer *player = getplayer(ref);
1324         if (player == NULL)
1325                 return 0;
1326
1327         u32 id = -1;
1328         if (!lua_isnil(L, 2))
1329                 id = lua_tonumber(L, 2);
1330
1331         if (!getServer(L)->hudRemove(player, id))
1332                 return 0;
1333
1334         lua_pushboolean(L, true);
1335         return 1;
1336 }
1337
1338 // hud_change(self, id, stat, data)
1339 int ObjectRef::l_hud_change(lua_State *L)
1340 {
1341         NO_MAP_LOCK_REQUIRED;
1342         ObjectRef *ref = checkobject(L, 1);
1343         RemotePlayer *player = getplayer(ref);
1344         if (player == NULL)
1345                 return 0;
1346
1347         u32 id = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : -1;
1348
1349         HudElement *e = player->getHud(id);
1350         if (!e)
1351                 return 0;
1352
1353         void *value = NULL;
1354         HudElementStat stat = read_hud_change(L, e, &value);
1355
1356         getServer(L)->hudChange(player, id, stat, value);
1357
1358         lua_pushboolean(L, true);
1359         return 1;
1360 }
1361
1362 // hud_get(self, id)
1363 int ObjectRef::l_hud_get(lua_State *L)
1364 {
1365         NO_MAP_LOCK_REQUIRED;
1366         ObjectRef *ref = checkobject(L, 1);
1367         RemotePlayer *player = getplayer(ref);
1368         if (player == NULL)
1369                 return 0;
1370
1371         u32 id = lua_tonumber(L, -1);
1372
1373         HudElement *e = player->getHud(id);
1374         if (!e)
1375                 return 0;
1376         push_hud_element(L, e);
1377         return 1;
1378 }
1379
1380 // hud_set_flags(self, flags)
1381 int ObjectRef::l_hud_set_flags(lua_State *L)
1382 {
1383         NO_MAP_LOCK_REQUIRED;
1384         ObjectRef *ref = checkobject(L, 1);
1385         RemotePlayer *player = getplayer(ref);
1386         if (player == NULL)
1387                 return 0;
1388
1389         u32 flags = 0;
1390         u32 mask  = 0;
1391         bool flag;
1392
1393         const EnumString *esp = es_HudBuiltinElement;
1394         for (int i = 0; esp[i].str; i++) {
1395                 if (getboolfield(L, 2, esp[i].str, flag)) {
1396                         flags |= esp[i].num * flag;
1397                         mask  |= esp[i].num;
1398                 }
1399         }
1400         if (!getServer(L)->hudSetFlags(player, flags, mask))
1401                 return 0;
1402
1403         lua_pushboolean(L, true);
1404         return 1;
1405 }
1406
1407 int ObjectRef::l_hud_get_flags(lua_State *L)
1408 {
1409         NO_MAP_LOCK_REQUIRED;
1410         ObjectRef *ref = checkobject(L, 1);
1411         RemotePlayer *player = getplayer(ref);
1412         if (player == NULL)
1413                 return 0;
1414
1415         lua_newtable(L);
1416         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
1417         lua_setfield(L, -2, "hotbar");
1418         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
1419         lua_setfield(L, -2, "healthbar");
1420         lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
1421         lua_setfield(L, -2, "crosshair");
1422         lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
1423         lua_setfield(L, -2, "wielditem");
1424         lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
1425         lua_setfield(L, -2, "breathbar");
1426         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1427         lua_setfield(L, -2, "minimap");
1428         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1429         lua_setfield(L, -2, "minimap_radar");
1430
1431         return 1;
1432 }
1433
1434 // hud_set_hotbar_itemcount(self, hotbar_itemcount)
1435 int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
1436 {
1437         NO_MAP_LOCK_REQUIRED;
1438         ObjectRef *ref = checkobject(L, 1);
1439         RemotePlayer *player = getplayer(ref);
1440         if (player == NULL)
1441                 return 0;
1442
1443         s32 hotbar_itemcount = lua_tonumber(L, 2);
1444
1445         if (!getServer(L)->hudSetHotbarItemcount(player, hotbar_itemcount))
1446                 return 0;
1447
1448         lua_pushboolean(L, true);
1449         return 1;
1450 }
1451
1452 // hud_get_hotbar_itemcount(self)
1453 int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
1454 {
1455         NO_MAP_LOCK_REQUIRED;
1456         ObjectRef *ref = checkobject(L, 1);
1457         RemotePlayer *player = getplayer(ref);
1458         if (player == NULL)
1459                 return 0;
1460
1461         lua_pushnumber(L, player->getHotbarItemcount());
1462         return 1;
1463 }
1464
1465 // hud_set_hotbar_image(self, name)
1466 int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
1467 {
1468         NO_MAP_LOCK_REQUIRED;
1469         ObjectRef *ref = checkobject(L, 1);
1470         RemotePlayer *player = getplayer(ref);
1471         if (player == NULL)
1472                 return 0;
1473
1474         std::string name = lua_tostring(L, 2);
1475
1476         getServer(L)->hudSetHotbarImage(player, name);
1477         return 1;
1478 }
1479
1480 // hud_get_hotbar_image(self)
1481 int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
1482 {
1483         NO_MAP_LOCK_REQUIRED;
1484         ObjectRef *ref = checkobject(L, 1);
1485         RemotePlayer *player = getplayer(ref);
1486         if (player == NULL)
1487                 return 0;
1488
1489         const std::string &name = player->getHotbarImage();
1490         lua_pushlstring(L, name.c_str(), name.size());
1491         return 1;
1492 }
1493
1494 // hud_set_hotbar_selected_image(self, name)
1495 int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
1496 {
1497         NO_MAP_LOCK_REQUIRED;
1498         ObjectRef *ref = checkobject(L, 1);
1499         RemotePlayer *player = getplayer(ref);
1500         if (player == NULL)
1501                 return 0;
1502
1503         std::string name = lua_tostring(L, 2);
1504
1505         getServer(L)->hudSetHotbarSelectedImage(player, name);
1506         return 1;
1507 }
1508
1509 // hud_get_hotbar_selected_image(self)
1510 int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
1511 {
1512         NO_MAP_LOCK_REQUIRED;
1513         ObjectRef *ref = checkobject(L, 1);
1514         RemotePlayer *player = getplayer(ref);
1515         if (player == NULL)
1516                 return 0;
1517
1518         const std::string &name = player->getHotbarSelectedImage();
1519         lua_pushlstring(L, name.c_str(), name.size());
1520         return 1;
1521 }
1522
1523 // set_sky(self, bgcolor, type, list, clouds = true)
1524 int ObjectRef::l_set_sky(lua_State *L)
1525 {
1526         NO_MAP_LOCK_REQUIRED;
1527         ObjectRef *ref = checkobject(L, 1);
1528         RemotePlayer *player = getplayer(ref);
1529         if (player == NULL)
1530                 return 0;
1531
1532         video::SColor bgcolor(255,255,255,255);
1533         read_color(L, 2, &bgcolor);
1534
1535         std::string type = luaL_checkstring(L, 3);
1536
1537         std::vector<std::string> params;
1538         if (lua_istable(L, 4)) {
1539                 lua_pushnil(L);
1540                 while (lua_next(L, 4) != 0) {
1541                         // key at index -2 and value at index -1
1542                         if (lua_isstring(L, -1))
1543                                 params.emplace_back(lua_tostring(L, -1));
1544                         else
1545                                 params.emplace_back("");
1546                         // removes value, keeps key for next iteration
1547                         lua_pop(L, 1);
1548                 }
1549         }
1550
1551         if (type == "skybox" && params.size() != 6)
1552                 throw LuaError("skybox expects 6 textures");
1553
1554         bool clouds = true;
1555         if (lua_isboolean(L, 5))
1556                 clouds = lua_toboolean(L, 5);
1557
1558         getServer(L)->setSky(player, bgcolor, type, params, clouds);
1559         lua_pushboolean(L, true);
1560         return 1;
1561 }
1562
1563 // get_sky(self)
1564 int ObjectRef::l_get_sky(lua_State *L)
1565 {
1566         NO_MAP_LOCK_REQUIRED;
1567         ObjectRef *ref = checkobject(L, 1);
1568         RemotePlayer *player = getplayer(ref);
1569         if (player == NULL)
1570                 return 0;
1571         video::SColor bgcolor(255, 255, 255, 255);
1572         std::string type;
1573         std::vector<std::string> params;
1574         bool clouds;
1575
1576         player->getSky(&bgcolor, &type, &params, &clouds);
1577         type = type.empty() ? "regular" : type;
1578
1579         push_ARGB8(L, bgcolor);
1580         lua_pushlstring(L, type.c_str(), type.size());
1581         lua_newtable(L);
1582         s16 i = 1;
1583         for (const std::string &param : params) {
1584                 lua_pushlstring(L, param.c_str(), param.size());
1585                 lua_rawseti(L, -2, i);
1586                 i++;
1587         }
1588         lua_pushboolean(L, clouds);
1589         return 4;
1590 }
1591
1592 // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
1593 int ObjectRef::l_set_clouds(lua_State *L)
1594 {
1595         NO_MAP_LOCK_REQUIRED;
1596         ObjectRef *ref = checkobject(L, 1);
1597         RemotePlayer *player = getplayer(ref);
1598         if (!player)
1599                 return 0;
1600         if (!lua_istable(L, 2))
1601                 return 0;
1602
1603         CloudParams cloud_params = player->getCloudParams();
1604
1605         cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
1606
1607         lua_getfield(L, 2, "color");
1608         if (!lua_isnil(L, -1))
1609                 read_color(L, -1, &cloud_params.color_bright);
1610         lua_pop(L, 1);
1611         lua_getfield(L, 2, "ambient");
1612         if (!lua_isnil(L, -1))
1613                 read_color(L, -1, &cloud_params.color_ambient);
1614         lua_pop(L, 1);
1615
1616         cloud_params.height    = getfloatfield_default(L, 2, "height",    cloud_params.height   );
1617         cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
1618
1619         lua_getfield(L, 2, "speed");
1620         if (lua_istable(L, -1)) {
1621                 v2f new_speed;
1622                 new_speed.X = getfloatfield_default(L, -1, "x", 0);
1623                 new_speed.Y = getfloatfield_default(L, -1, "z", 0);
1624                 cloud_params.speed = new_speed;
1625         }
1626         lua_pop(L, 1);
1627
1628         getServer(L)->setClouds(player, cloud_params);
1629         lua_pushboolean(L, true);
1630         return 1;
1631 }
1632
1633 int ObjectRef::l_get_clouds(lua_State *L)
1634 {
1635         NO_MAP_LOCK_REQUIRED;
1636         ObjectRef *ref = checkobject(L, 1);
1637         RemotePlayer *player = getplayer(ref);
1638         if (!player)
1639                 return 0;
1640         const CloudParams &cloud_params = player->getCloudParams();
1641
1642         lua_newtable(L);
1643         lua_pushnumber(L, cloud_params.density);
1644         lua_setfield(L, -2, "density");
1645         push_ARGB8(L, cloud_params.color_bright);
1646         lua_setfield(L, -2, "color");
1647         push_ARGB8(L, cloud_params.color_ambient);
1648         lua_setfield(L, -2, "ambient");
1649         lua_pushnumber(L, cloud_params.height);
1650         lua_setfield(L, -2, "height");
1651         lua_pushnumber(L, cloud_params.thickness);
1652         lua_setfield(L, -2, "thickness");
1653         lua_newtable(L);
1654         lua_pushnumber(L, cloud_params.speed.X);
1655         lua_setfield(L, -2, "x");
1656         lua_pushnumber(L, cloud_params.speed.Y);
1657         lua_setfield(L, -2, "y");
1658         lua_setfield(L, -2, "speed");
1659
1660         return 1;
1661 }
1662
1663
1664 // override_day_night_ratio(self, brightness=0...1)
1665 int ObjectRef::l_override_day_night_ratio(lua_State *L)
1666 {
1667         NO_MAP_LOCK_REQUIRED;
1668         ObjectRef *ref = checkobject(L, 1);
1669         RemotePlayer *player = getplayer(ref);
1670         if (player == NULL)
1671                 return 0;
1672
1673         bool do_override = false;
1674         float ratio = 0.0f;
1675         if (!lua_isnil(L, 2)) {
1676                 do_override = true;
1677                 ratio = luaL_checknumber(L, 2);
1678         }
1679
1680         if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio))
1681                 return 0;
1682
1683         lua_pushboolean(L, true);
1684         return 1;
1685 }
1686
1687 // get_day_night_ratio(self)
1688 int ObjectRef::l_get_day_night_ratio(lua_State *L)
1689 {
1690         NO_MAP_LOCK_REQUIRED;
1691         ObjectRef *ref = checkobject(L, 1);
1692         RemotePlayer *player = getplayer(ref);
1693         if (player == NULL)
1694                 return 0;
1695
1696         bool do_override;
1697         float ratio;
1698         player->getDayNightRatio(&do_override, &ratio);
1699
1700         if (do_override)
1701                 lua_pushnumber(L, ratio);
1702         else
1703                 lua_pushnil(L);
1704
1705         return 1;
1706 }
1707
1708 ObjectRef::ObjectRef(ServerActiveObject *object):
1709         m_object(object)
1710 {
1711         //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
1712 }
1713
1714 // Creates an ObjectRef and leaves it on top of stack
1715 // Not callable from Lua; all references are created on the C side.
1716 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
1717 {
1718         ObjectRef *o = new ObjectRef(object);
1719         //infostream<<"ObjectRef::create: o="<<o<<std::endl;
1720         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
1721         luaL_getmetatable(L, className);
1722         lua_setmetatable(L, -2);
1723 }
1724
1725 void ObjectRef::set_null(lua_State *L)
1726 {
1727         ObjectRef *o = checkobject(L, -1);
1728         o->m_object = NULL;
1729 }
1730
1731 void ObjectRef::Register(lua_State *L)
1732 {
1733         lua_newtable(L);
1734         int methodtable = lua_gettop(L);
1735         luaL_newmetatable(L, className);
1736         int metatable = lua_gettop(L);
1737
1738         lua_pushliteral(L, "__metatable");
1739         lua_pushvalue(L, methodtable);
1740         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
1741
1742         lua_pushliteral(L, "__index");
1743         lua_pushvalue(L, methodtable);
1744         lua_settable(L, metatable);
1745
1746         lua_pushliteral(L, "__gc");
1747         lua_pushcfunction(L, gc_object);
1748         lua_settable(L, metatable);
1749
1750         lua_pop(L, 1);  // drop metatable
1751
1752         luaL_openlib(L, 0, methods, 0);  // fill methodtable
1753         lua_pop(L, 1);  // drop methodtable
1754
1755         // Cannot be created from Lua
1756         //lua_register(L, className, create_object);
1757 }
1758
1759 const char ObjectRef::className[] = "ObjectRef";
1760 const luaL_Reg ObjectRef::methods[] = {
1761         // ServerActiveObject
1762         luamethod(ObjectRef, remove),
1763         luamethod_aliased(ObjectRef, get_pos, getpos),
1764         luamethod_aliased(ObjectRef, set_pos, setpos),
1765         luamethod_aliased(ObjectRef, move_to, moveto),
1766         luamethod(ObjectRef, punch),
1767         luamethod(ObjectRef, right_click),
1768         luamethod(ObjectRef, set_hp),
1769         luamethod(ObjectRef, get_hp),
1770         luamethod(ObjectRef, get_inventory),
1771         luamethod(ObjectRef, get_wield_list),
1772         luamethod(ObjectRef, get_wield_index),
1773         luamethod(ObjectRef, get_wielded_item),
1774         luamethod(ObjectRef, set_wielded_item),
1775         luamethod(ObjectRef, set_armor_groups),
1776         luamethod(ObjectRef, get_armor_groups),
1777         luamethod(ObjectRef, set_animation),
1778         luamethod(ObjectRef, get_animation),
1779         luamethod(ObjectRef, set_animation_frame_speed),
1780         luamethod(ObjectRef, set_bone_position),
1781         luamethod(ObjectRef, get_bone_position),
1782         luamethod(ObjectRef, set_attach),
1783         luamethod(ObjectRef, get_attach),
1784         luamethod(ObjectRef, set_detach),
1785         luamethod(ObjectRef, set_properties),
1786         luamethod(ObjectRef, get_properties),
1787         luamethod(ObjectRef, set_nametag_attributes),
1788         luamethod(ObjectRef, get_nametag_attributes),
1789         // LuaEntitySAO-only
1790         luamethod_aliased(ObjectRef, set_velocity, setvelocity),
1791         luamethod_aliased(ObjectRef, get_velocity, getvelocity),
1792         luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
1793         luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
1794         luamethod_aliased(ObjectRef, set_yaw, setyaw),
1795         luamethod_aliased(ObjectRef, get_yaw, getyaw),
1796         luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
1797         luamethod_aliased(ObjectRef, set_sprite, setsprite),
1798         luamethod(ObjectRef, get_entity_name),
1799         luamethod(ObjectRef, get_luaentity),
1800         // Player-only
1801         luamethod(ObjectRef, is_player),
1802         luamethod(ObjectRef, is_player_connected),
1803         luamethod(ObjectRef, get_player_name),
1804         luamethod(ObjectRef, get_player_velocity),
1805         luamethod(ObjectRef, get_look_dir),
1806         luamethod(ObjectRef, get_look_pitch),
1807         luamethod(ObjectRef, get_look_yaw),
1808         luamethod(ObjectRef, get_look_vertical),
1809         luamethod(ObjectRef, get_look_horizontal),
1810         luamethod(ObjectRef, set_look_horizontal),
1811         luamethod(ObjectRef, set_look_vertical),
1812         luamethod(ObjectRef, set_look_yaw),
1813         luamethod(ObjectRef, set_look_pitch),
1814         luamethod(ObjectRef, get_breath),
1815         luamethod(ObjectRef, set_breath),
1816         luamethod(ObjectRef, get_attribute),
1817         luamethod(ObjectRef, set_attribute),
1818         luamethod(ObjectRef, set_inventory_formspec),
1819         luamethod(ObjectRef, get_inventory_formspec),
1820         luamethod(ObjectRef, get_player_control),
1821         luamethod(ObjectRef, get_player_control_bits),
1822         luamethod(ObjectRef, set_physics_override),
1823         luamethod(ObjectRef, get_physics_override),
1824         luamethod(ObjectRef, hud_add),
1825         luamethod(ObjectRef, hud_remove),
1826         luamethod(ObjectRef, hud_change),
1827         luamethod(ObjectRef, hud_get),
1828         luamethod(ObjectRef, hud_set_flags),
1829         luamethod(ObjectRef, hud_get_flags),
1830         luamethod(ObjectRef, hud_set_hotbar_itemcount),
1831         luamethod(ObjectRef, hud_get_hotbar_itemcount),
1832         luamethod(ObjectRef, hud_set_hotbar_image),
1833         luamethod(ObjectRef, hud_get_hotbar_image),
1834         luamethod(ObjectRef, hud_set_hotbar_selected_image),
1835         luamethod(ObjectRef, hud_get_hotbar_selected_image),
1836         luamethod(ObjectRef, set_sky),
1837         luamethod(ObjectRef, get_sky),
1838         luamethod(ObjectRef, set_clouds),
1839         luamethod(ObjectRef, get_clouds),
1840         luamethod(ObjectRef, override_day_night_ratio),
1841         luamethod(ObjectRef, get_day_night_ratio),
1842         luamethod(ObjectRef, set_local_animation),
1843         luamethod(ObjectRef, get_local_animation),
1844         luamethod(ObjectRef, set_eye_offset),
1845         luamethod(ObjectRef, get_eye_offset),
1846         {0,0}
1847 };