]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_object.cpp
[CSM] Add basic HUD manipulation. (#6067)
[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         if (!getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed))
497                 return 0;
498
499         lua_pushboolean(L, true);
500         return 0;
501 }
502
503 // get_local_animation(self)
504 int ObjectRef::l_get_local_animation(lua_State *L)
505 {
506         NO_MAP_LOCK_REQUIRED
507         ObjectRef *ref = checkobject(L, 1);
508         RemotePlayer *player = getplayer(ref);
509         if (player == NULL)
510                 return 0;
511
512         v2s32 frames[4];
513         float frame_speed;
514         player->getLocalAnimations(frames, &frame_speed);
515
516         for (const v2s32 &frame : frames) {
517                 push_v2s32(L, frame);
518         }
519
520         lua_pushnumber(L, frame_speed);
521         return 5;
522 }
523
524 // set_eye_offset(self, v3f first pv, v3f third pv)
525 int ObjectRef::l_set_eye_offset(lua_State *L)
526 {
527         NO_MAP_LOCK_REQUIRED;
528         ObjectRef *ref = checkobject(L, 1);
529         RemotePlayer *player = getplayer(ref);
530         if (player == NULL)
531                 return 0;
532         // Do it
533         v3f offset_first = v3f(0, 0, 0);
534         v3f offset_third = v3f(0, 0, 0);
535
536         if (!lua_isnil(L, 2))
537                 offset_first = read_v3f(L, 2);
538         if (!lua_isnil(L, 3))
539                 offset_third = read_v3f(L, 3);
540
541         // Prevent abuse of offset values (keep player always visible)
542         offset_third.X = rangelim(offset_third.X,-10,10);
543         offset_third.Z = rangelim(offset_third.Z,-5,5);
544         /* TODO: if possible: improve the camera colision detetion to allow Y <= -1.5) */
545         offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS
546
547         if (!getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third))
548                 return 0;
549
550         lua_pushboolean(L, true);
551         return 0;
552 }
553
554 // get_eye_offset(self)
555 int ObjectRef::l_get_eye_offset(lua_State *L)
556 {
557         NO_MAP_LOCK_REQUIRED;
558         ObjectRef *ref = checkobject(L, 1);
559         RemotePlayer *player = getplayer(ref);
560         if (player == NULL)
561                 return 0;
562         // Do it
563         push_v3f(L, player->eye_offset_first);
564         push_v3f(L, player->eye_offset_third);
565         return 2;
566 }
567
568 // set_animation_frame_speed(self, frame_speed)
569 int ObjectRef::l_set_animation_frame_speed(lua_State *L)
570 {
571         NO_MAP_LOCK_REQUIRED;
572         ObjectRef *ref = checkobject(L, 1);
573         ServerActiveObject *co = getobject(ref);
574         if (co == NULL)
575                 return 0;
576
577         // Do it
578         if (!lua_isnil(L, 2)) {
579                 float frame_speed = lua_tonumber(L, 2);
580                 co->setAnimationSpeed(frame_speed);
581                 lua_pushboolean(L, true);
582         } else {
583                 lua_pushboolean(L, false);
584         }
585         return 1;
586 }
587
588 // set_bone_position(self, std::string bone, v3f position, v3f rotation)
589 int ObjectRef::l_set_bone_position(lua_State *L)
590 {
591         NO_MAP_LOCK_REQUIRED;
592         ObjectRef *ref = checkobject(L, 1);
593         ServerActiveObject *co = getobject(ref);
594         if (co == NULL) return 0;
595         // Do it
596         std::string bone;
597         if (!lua_isnil(L, 2))
598                 bone = lua_tostring(L, 2);
599         v3f position = v3f(0, 0, 0);
600         if (!lua_isnil(L, 3))
601                 position = check_v3f(L, 3);
602         v3f rotation = v3f(0, 0, 0);
603         if (!lua_isnil(L, 4))
604                 rotation = check_v3f(L, 4);
605         co->setBonePosition(bone, position, rotation);
606         return 0;
607 }
608
609 // get_bone_position(self, bone)
610 int ObjectRef::l_get_bone_position(lua_State *L)
611 {
612         NO_MAP_LOCK_REQUIRED;
613         ObjectRef *ref = checkobject(L, 1);
614         ServerActiveObject *co = getobject(ref);
615         if (co == NULL)
616                 return 0;
617         // Do it
618         std::string bone;
619         if (!lua_isnil(L, 2))
620                 bone = lua_tostring(L, 2);
621
622         v3f position = v3f(0, 0, 0);
623         v3f rotation = v3f(0, 0, 0);
624         co->getBonePosition(bone, &position, &rotation);
625
626         push_v3f(L, position);
627         push_v3f(L, rotation);
628         return 2;
629 }
630
631 // set_attach(self, parent, bone, position, rotation)
632 int ObjectRef::l_set_attach(lua_State *L)
633 {
634         GET_ENV_PTR;
635
636         ObjectRef *ref = checkobject(L, 1);
637         ObjectRef *parent_ref = checkobject(L, 2);
638         ServerActiveObject *co = getobject(ref);
639         ServerActiveObject *parent = getobject(parent_ref);
640         if (co == NULL)
641                 return 0;
642         if (parent == NULL)
643                 return 0;
644         // Do it
645         int parent_id = 0;
646         std::string bone;
647         v3f position = v3f(0, 0, 0);
648         v3f rotation = v3f(0, 0, 0);
649         co->getAttachment(&parent_id, &bone, &position, &rotation);
650         if (parent_id) {
651                 ServerActiveObject *old_parent = env->getActiveObject(parent_id);
652                 old_parent->removeAttachmentChild(co->getId());
653         }
654
655         bone = "";
656         if (!lua_isnil(L, 3))
657                 bone = lua_tostring(L, 3);
658         position = v3f(0, 0, 0);
659         if (!lua_isnil(L, 4))
660                 position = read_v3f(L, 4);
661         rotation = v3f(0, 0, 0);
662         if (!lua_isnil(L, 5))
663                 rotation = read_v3f(L, 5);
664         co->setAttachment(parent->getId(), bone, position, rotation);
665         parent->addAttachmentChild(co->getId());
666         return 0;
667 }
668
669 // get_attach(self)
670 int ObjectRef::l_get_attach(lua_State *L)
671 {
672         GET_ENV_PTR;
673
674         ObjectRef *ref = checkobject(L, 1);
675         ServerActiveObject *co = getobject(ref);
676         if (co == NULL)
677                 return 0;
678
679         // Do it
680         int parent_id = 0;
681         std::string bone;
682         v3f position = v3f(0, 0, 0);
683         v3f rotation = v3f(0, 0, 0);
684         co->getAttachment(&parent_id, &bone, &position, &rotation);
685         if (!parent_id)
686                 return 0;
687         ServerActiveObject *parent = env->getActiveObject(parent_id);
688
689         getScriptApiBase(L)->objectrefGetOrCreate(L, parent);
690         lua_pushlstring(L, bone.c_str(), bone.size());
691         push_v3f(L, position);
692         push_v3f(L, rotation);
693         return 4;
694 }
695
696 // set_detach(self)
697 int ObjectRef::l_set_detach(lua_State *L)
698 {
699         GET_ENV_PTR;
700
701         ObjectRef *ref = checkobject(L, 1);
702         ServerActiveObject *co = getobject(ref);
703         if (co == NULL)
704                 return 0;
705
706         int parent_id = 0;
707         std::string bone;
708         v3f position;
709         v3f rotation;
710         co->getAttachment(&parent_id, &bone, &position, &rotation);
711         ServerActiveObject *parent = NULL;
712         if (parent_id) {
713                 parent = env->getActiveObject(parent_id);
714                 co->setAttachment(0, "", position, rotation);
715         } else {
716                 co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
717         }
718         // Do it
719         if (parent != NULL)
720                 parent->removeAttachmentChild(co->getId());
721         return 0;
722 }
723
724 // set_properties(self, properties)
725 int ObjectRef::l_set_properties(lua_State *L)
726 {
727         NO_MAP_LOCK_REQUIRED;
728         ObjectRef *ref = checkobject(L, 1);
729         ServerActiveObject *co = getobject(ref);
730         if (co == NULL) return 0;
731         ObjectProperties *prop = co->accessObjectProperties();
732         if (!prop)
733                 return 0;
734         read_object_properties(L, 2, prop, getServer(L)->idef());
735         if (prop->hp_max < co->getHP()) {
736                 co->setHP(prop->hp_max);
737                 if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
738                         getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
739         }
740         co->notifyObjectPropertiesModified();
741         return 0;
742 }
743
744 // get_properties(self)
745 int ObjectRef::l_get_properties(lua_State *L)
746 {
747         NO_MAP_LOCK_REQUIRED;
748         ObjectRef *ref = checkobject(L, 1);
749         ServerActiveObject *co = getobject(ref);
750         if (co == NULL)
751                 return 0;
752         ObjectProperties *prop = co->accessObjectProperties();
753         if (!prop)
754                 return 0;
755         push_object_properties(L, prop);
756         return 1;
757 }
758
759 // is_player(self)
760 int ObjectRef::l_is_player(lua_State *L)
761 {
762         NO_MAP_LOCK_REQUIRED;
763         ObjectRef *ref = checkobject(L, 1);
764         RemotePlayer *player = getplayer(ref);
765         lua_pushboolean(L, (player != NULL));
766         return 1;
767 }
768
769 // set_nametag_attributes(self, attributes)
770 int ObjectRef::l_set_nametag_attributes(lua_State *L)
771 {
772         NO_MAP_LOCK_REQUIRED;
773         ObjectRef *ref = checkobject(L, 1);
774         ServerActiveObject *co = getobject(ref);
775
776         if (co == NULL)
777                 return 0;
778         ObjectProperties *prop = co->accessObjectProperties();
779         if (!prop)
780                 return 0;
781
782         lua_getfield(L, 2, "color");
783         if (!lua_isnil(L, -1)) {
784                 video::SColor color = prop->nametag_color;
785                 read_color(L, -1, &color);
786                 prop->nametag_color = color;
787         }
788         lua_pop(L, 1);
789
790         std::string nametag = getstringfield_default(L, 2, "text", "");
791         prop->nametag = nametag;
792
793         co->notifyObjectPropertiesModified();
794         lua_pushboolean(L, true);
795         return 1;
796 }
797
798 // get_nametag_attributes(self)
799 int ObjectRef::l_get_nametag_attributes(lua_State *L)
800 {
801         NO_MAP_LOCK_REQUIRED;
802         ObjectRef *ref = checkobject(L, 1);
803         ServerActiveObject *co = getobject(ref);
804
805         if (co == NULL)
806                 return 0;
807         ObjectProperties *prop = co->accessObjectProperties();
808         if (!prop)
809                 return 0;
810
811         video::SColor color = prop->nametag_color;
812
813         lua_newtable(L);
814         push_ARGB8(L, color);
815         lua_setfield(L, -2, "color");
816         lua_pushstring(L, prop->nametag.c_str());
817         lua_setfield(L, -2, "text");
818         return 1;
819 }
820
821 /* LuaEntitySAO-only */
822
823 // set_velocity(self, {x=num, y=num, z=num})
824 int ObjectRef::l_set_velocity(lua_State *L)
825 {
826         NO_MAP_LOCK_REQUIRED;
827         ObjectRef *ref = checkobject(L, 1);
828         LuaEntitySAO *co = getluaobject(ref);
829         if (co == NULL) return 0;
830         v3f pos = checkFloatPos(L, 2);
831         // Do it
832         co->setVelocity(pos);
833         return 0;
834 }
835
836 // get_velocity(self)
837 int ObjectRef::l_get_velocity(lua_State *L)
838 {
839         NO_MAP_LOCK_REQUIRED;
840         ObjectRef *ref = checkobject(L, 1);
841         LuaEntitySAO *co = getluaobject(ref);
842         if (co == NULL) return 0;
843         // Do it
844         v3f v = co->getVelocity();
845         pushFloatPos(L, v);
846         return 1;
847 }
848
849 // set_acceleration(self, {x=num, y=num, z=num})
850 int ObjectRef::l_set_acceleration(lua_State *L)
851 {
852         NO_MAP_LOCK_REQUIRED;
853         ObjectRef *ref = checkobject(L, 1);
854         LuaEntitySAO *co = getluaobject(ref);
855         if (co == NULL) return 0;
856         // pos
857         v3f pos = checkFloatPos(L, 2);
858         // Do it
859         co->setAcceleration(pos);
860         return 0;
861 }
862
863 // get_acceleration(self)
864 int ObjectRef::l_get_acceleration(lua_State *L)
865 {
866         NO_MAP_LOCK_REQUIRED;
867         ObjectRef *ref = checkobject(L, 1);
868         LuaEntitySAO *co = getluaobject(ref);
869         if (co == NULL) return 0;
870         // Do it
871         v3f v = co->getAcceleration();
872         pushFloatPos(L, v);
873         return 1;
874 }
875
876 // set_yaw(self, radians)
877 int ObjectRef::l_set_yaw(lua_State *L)
878 {
879         NO_MAP_LOCK_REQUIRED;
880         ObjectRef *ref = checkobject(L, 1);
881         LuaEntitySAO *co = getluaobject(ref);
882         if (co == NULL) return 0;
883         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
884         // Do it
885         co->setYaw(yaw);
886         return 0;
887 }
888
889 // get_yaw(self)
890 int ObjectRef::l_get_yaw(lua_State *L)
891 {
892         NO_MAP_LOCK_REQUIRED;
893         ObjectRef *ref = checkobject(L, 1);
894         LuaEntitySAO *co = getluaobject(ref);
895         if (co == NULL) return 0;
896         // Do it
897         float yaw = co->getYaw() * core::DEGTORAD;
898         lua_pushnumber(L, yaw);
899         return 1;
900 }
901
902 // set_texture_mod(self, mod)
903 int ObjectRef::l_set_texture_mod(lua_State *L)
904 {
905         NO_MAP_LOCK_REQUIRED;
906         ObjectRef *ref = checkobject(L, 1);
907         LuaEntitySAO *co = getluaobject(ref);
908         if (co == NULL) return 0;
909         // Do it
910         std::string mod = luaL_checkstring(L, 2);
911         co->setTextureMod(mod);
912         return 0;
913 }
914
915 // get_texture_mod(self)
916 int ObjectRef::l_get_texture_mod(lua_State *L)
917 {
918         NO_MAP_LOCK_REQUIRED;
919         ObjectRef *ref = checkobject(L, 1);
920         LuaEntitySAO *co = getluaobject(ref);
921         if (co == NULL) return 0;
922         // Do it
923         std::string mod = co->getTextureMod();
924         lua_pushstring(L, mod.c_str());
925         return 1;
926 }
927
928 // set_sprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
929 //           select_horiz_by_yawpitch=false)
930 int ObjectRef::l_set_sprite(lua_State *L)
931 {
932         NO_MAP_LOCK_REQUIRED;
933         ObjectRef *ref = checkobject(L, 1);
934         LuaEntitySAO *co = getluaobject(ref);
935         if (co == NULL) return 0;
936         // Do it
937         v2s16 p(0,0);
938         if (!lua_isnil(L, 2))
939                 p = read_v2s16(L, 2);
940         int num_frames = 1;
941         if (!lua_isnil(L, 3))
942                 num_frames = lua_tonumber(L, 3);
943         float framelength = 0.2;
944         if (!lua_isnil(L, 4))
945                 framelength = lua_tonumber(L, 4);
946         bool select_horiz_by_yawpitch = false;
947         if (!lua_isnil(L, 5))
948                 select_horiz_by_yawpitch = lua_toboolean(L, 5);
949         co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
950         return 0;
951 }
952
953 // DEPRECATED
954 // get_entity_name(self)
955 int ObjectRef::l_get_entity_name(lua_State *L)
956 {
957         NO_MAP_LOCK_REQUIRED;
958         ObjectRef *ref = checkobject(L, 1);
959         LuaEntitySAO *co = getluaobject(ref);
960         log_deprecated(L,"Deprecated call to \"get_entity_name");
961         if (co == NULL) return 0;
962         // Do it
963         std::string name = co->getName();
964         lua_pushstring(L, name.c_str());
965         return 1;
966 }
967
968 // get_luaentity(self)
969 int ObjectRef::l_get_luaentity(lua_State *L)
970 {
971         NO_MAP_LOCK_REQUIRED;
972         ObjectRef *ref = checkobject(L, 1);
973         LuaEntitySAO *co = getluaobject(ref);
974         if (co == NULL) return 0;
975         // Do it
976         luaentity_get(L, co->getId());
977         return 1;
978 }
979
980 /* Player-only */
981
982 // is_player_connected(self)
983 int ObjectRef::l_is_player_connected(lua_State *L)
984 {
985         NO_MAP_LOCK_REQUIRED;
986         ObjectRef *ref = checkobject(L, 1);
987         RemotePlayer *player = getplayer(ref);
988         lua_pushboolean(L, (player != NULL && player->getPeerId() != PEER_ID_INEXISTENT));
989         return 1;
990 }
991
992 // get_player_name(self)
993 int ObjectRef::l_get_player_name(lua_State *L)
994 {
995         NO_MAP_LOCK_REQUIRED;
996         ObjectRef *ref = checkobject(L, 1);
997         RemotePlayer *player = getplayer(ref);
998         if (player == NULL) {
999                 lua_pushlstring(L, "", 0);
1000                 return 1;
1001         }
1002         // Do it
1003         lua_pushstring(L, player->getName());
1004         return 1;
1005 }
1006
1007 // get_player_velocity(self)
1008 int ObjectRef::l_get_player_velocity(lua_State *L)
1009 {
1010         NO_MAP_LOCK_REQUIRED;
1011         ObjectRef *ref = checkobject(L, 1);
1012         RemotePlayer *player = getplayer(ref);
1013         if (player == NULL) {
1014                 lua_pushnil(L);
1015                 return 1;
1016         }
1017         // Do it
1018         push_v3f(L, player->getSpeed() / BS);
1019         return 1;
1020 }
1021
1022 // get_look_dir(self)
1023 int ObjectRef::l_get_look_dir(lua_State *L)
1024 {
1025         NO_MAP_LOCK_REQUIRED;
1026         ObjectRef *ref = checkobject(L, 1);
1027         PlayerSAO* co = getplayersao(ref);
1028         if (co == NULL) return 0;
1029         // Do it
1030         float pitch = co->getRadPitchDep();
1031         float yaw = co->getRadYawDep();
1032         v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw));
1033         push_v3f(L, v);
1034         return 1;
1035 }
1036
1037 // DEPRECATED
1038 // get_look_pitch(self)
1039 int ObjectRef::l_get_look_pitch(lua_State *L)
1040 {
1041         NO_MAP_LOCK_REQUIRED;
1042
1043         log_deprecated(L,
1044                 "Deprecated call to get_look_pitch, use get_look_vertical instead");
1045
1046         ObjectRef *ref = checkobject(L, 1);
1047         PlayerSAO* co = getplayersao(ref);
1048         if (co == NULL) return 0;
1049         // Do it
1050         lua_pushnumber(L, co->getRadPitchDep());
1051         return 1;
1052 }
1053
1054 // DEPRECATED
1055 // get_look_yaw(self)
1056 int ObjectRef::l_get_look_yaw(lua_State *L)
1057 {
1058         NO_MAP_LOCK_REQUIRED;
1059
1060         log_deprecated(L,
1061                 "Deprecated call to get_look_yaw, use get_look_horizontal instead");
1062
1063         ObjectRef *ref = checkobject(L, 1);
1064         PlayerSAO* co = getplayersao(ref);
1065         if (co == NULL) return 0;
1066         // Do it
1067         lua_pushnumber(L, co->getRadYawDep());
1068         return 1;
1069 }
1070
1071 // get_look_pitch2(self)
1072 int ObjectRef::l_get_look_vertical(lua_State *L)
1073 {
1074         NO_MAP_LOCK_REQUIRED;
1075         ObjectRef *ref = checkobject(L, 1);
1076         PlayerSAO* co = getplayersao(ref);
1077         if (co == NULL) return 0;
1078         // Do it
1079         lua_pushnumber(L, co->getRadPitch());
1080         return 1;
1081 }
1082
1083 // get_look_yaw2(self)
1084 int ObjectRef::l_get_look_horizontal(lua_State *L)
1085 {
1086         NO_MAP_LOCK_REQUIRED;
1087         ObjectRef *ref = checkobject(L, 1);
1088         PlayerSAO* co = getplayersao(ref);
1089         if (co == NULL) return 0;
1090         // Do it
1091         lua_pushnumber(L, co->getRadYaw());
1092         return 1;
1093 }
1094
1095 // set_look_vertical(self, radians)
1096 int ObjectRef::l_set_look_vertical(lua_State *L)
1097 {
1098         NO_MAP_LOCK_REQUIRED;
1099         ObjectRef *ref = checkobject(L, 1);
1100         PlayerSAO* co = getplayersao(ref);
1101         if (co == NULL) return 0;
1102         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1103         // Do it
1104         co->setPitchAndSend(pitch);
1105         return 1;
1106 }
1107
1108 // set_look_horizontal(self, radians)
1109 int ObjectRef::l_set_look_horizontal(lua_State *L)
1110 {
1111         NO_MAP_LOCK_REQUIRED;
1112         ObjectRef *ref = checkobject(L, 1);
1113         PlayerSAO* co = getplayersao(ref);
1114         if (co == NULL) return 0;
1115         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1116         // Do it
1117         co->setYawAndSend(yaw);
1118         return 1;
1119 }
1120
1121 // DEPRECATED
1122 // set_look_pitch(self, radians)
1123 int ObjectRef::l_set_look_pitch(lua_State *L)
1124 {
1125         NO_MAP_LOCK_REQUIRED;
1126
1127         log_deprecated(L,
1128                 "Deprecated call to set_look_pitch, use set_look_vertical instead.");
1129
1130         ObjectRef *ref = checkobject(L, 1);
1131         PlayerSAO* co = getplayersao(ref);
1132         if (co == NULL) return 0;
1133         float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
1134         // Do it
1135         co->setPitchAndSend(pitch);
1136         return 1;
1137 }
1138
1139 // DEPRECATED
1140 // set_look_yaw(self, radians)
1141 int ObjectRef::l_set_look_yaw(lua_State *L)
1142 {
1143         NO_MAP_LOCK_REQUIRED;
1144
1145         log_deprecated(L,
1146                 "Deprecated call to set_look_yaw, use set_look_horizontal instead.");
1147
1148         ObjectRef *ref = checkobject(L, 1);
1149         PlayerSAO* co = getplayersao(ref);
1150         if (co == NULL) return 0;
1151         float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
1152         // Do it
1153         co->setYawAndSend(yaw);
1154         return 1;
1155 }
1156
1157 // set_breath(self, breath)
1158 int ObjectRef::l_set_breath(lua_State *L)
1159 {
1160         NO_MAP_LOCK_REQUIRED;
1161         ObjectRef *ref = checkobject(L, 1);
1162         PlayerSAO* co = getplayersao(ref);
1163         if (co == NULL) return 0;
1164         u16 breath = luaL_checknumber(L, 2);
1165         co->setBreath(breath);
1166
1167         return 0;
1168 }
1169
1170 // get_breath(self)
1171 int ObjectRef::l_get_breath(lua_State *L)
1172 {
1173         NO_MAP_LOCK_REQUIRED;
1174         ObjectRef *ref = checkobject(L, 1);
1175         PlayerSAO* co = getplayersao(ref);
1176         if (co == NULL) return 0;
1177         // Do it
1178         u16 breath = co->getBreath();
1179         lua_pushinteger (L, breath);
1180         return 1;
1181 }
1182
1183 // set_attribute(self, attribute, value)
1184 int ObjectRef::l_set_attribute(lua_State *L)
1185 {
1186         ObjectRef *ref = checkobject(L, 1);
1187         PlayerSAO* co = getplayersao(ref);
1188         if (co == NULL) {
1189                 return 0;
1190         }
1191
1192         std::string attr = luaL_checkstring(L, 2);
1193         if (lua_isnil(L, 3)) {
1194                 co->removeExtendedAttribute(attr);
1195         } else {
1196                 std::string value = luaL_checkstring(L, 3);
1197                 co->setExtendedAttribute(attr, value);
1198         }
1199         return 1;
1200 }
1201
1202 // get_attribute(self, attribute)
1203 int ObjectRef::l_get_attribute(lua_State *L)
1204 {
1205         ObjectRef *ref = checkobject(L, 1);
1206         PlayerSAO* co = getplayersao(ref);
1207         if (co == NULL) {
1208                 return 0;
1209         }
1210
1211         std::string attr = luaL_checkstring(L, 2);
1212
1213         std::string value;
1214         if (co->getExtendedAttribute(attr, &value)) {
1215                 lua_pushstring(L, value.c_str());
1216                 return 1;
1217         }
1218
1219         return 0;
1220 }
1221
1222
1223 // set_inventory_formspec(self, formspec)
1224 int ObjectRef::l_set_inventory_formspec(lua_State *L)
1225 {
1226         NO_MAP_LOCK_REQUIRED;
1227         ObjectRef *ref = checkobject(L, 1);
1228         RemotePlayer *player = getplayer(ref);
1229         if (player == NULL) return 0;
1230         std::string formspec = luaL_checkstring(L, 2);
1231
1232         player->inventory_formspec = formspec;
1233         getServer(L)->reportInventoryFormspecModified(player->getName());
1234         lua_pushboolean(L, true);
1235         return 1;
1236 }
1237
1238 // get_inventory_formspec(self) -> formspec
1239 int ObjectRef::l_get_inventory_formspec(lua_State *L)
1240 {
1241         NO_MAP_LOCK_REQUIRED;
1242         ObjectRef *ref = checkobject(L, 1);
1243         RemotePlayer *player = getplayer(ref);
1244         if (player == NULL) return 0;
1245
1246         std::string formspec = player->inventory_formspec;
1247         lua_pushlstring(L, formspec.c_str(), formspec.size());
1248         return 1;
1249 }
1250
1251 // get_player_control(self)
1252 int ObjectRef::l_get_player_control(lua_State *L)
1253 {
1254         NO_MAP_LOCK_REQUIRED;
1255         ObjectRef *ref = checkobject(L, 1);
1256         RemotePlayer *player = getplayer(ref);
1257         if (player == NULL) {
1258                 lua_pushlstring(L, "", 0);
1259                 return 1;
1260         }
1261
1262         const PlayerControl &control = player->getPlayerControl();
1263         lua_newtable(L);
1264         lua_pushboolean(L, control.up);
1265         lua_setfield(L, -2, "up");
1266         lua_pushboolean(L, control.down);
1267         lua_setfield(L, -2, "down");
1268         lua_pushboolean(L, control.left);
1269         lua_setfield(L, -2, "left");
1270         lua_pushboolean(L, control.right);
1271         lua_setfield(L, -2, "right");
1272         lua_pushboolean(L, control.jump);
1273         lua_setfield(L, -2, "jump");
1274         lua_pushboolean(L, control.aux1);
1275         lua_setfield(L, -2, "aux1");
1276         lua_pushboolean(L, control.sneak);
1277         lua_setfield(L, -2, "sneak");
1278         lua_pushboolean(L, control.LMB);
1279         lua_setfield(L, -2, "LMB");
1280         lua_pushboolean(L, control.RMB);
1281         lua_setfield(L, -2, "RMB");
1282         return 1;
1283 }
1284
1285 // get_player_control_bits(self)
1286 int ObjectRef::l_get_player_control_bits(lua_State *L)
1287 {
1288         NO_MAP_LOCK_REQUIRED;
1289         ObjectRef *ref = checkobject(L, 1);
1290         RemotePlayer *player = getplayer(ref);
1291         if (player == NULL) {
1292                 lua_pushlstring(L, "", 0);
1293                 return 1;
1294         }
1295         // Do it
1296         lua_pushnumber(L, player->keyPressed);
1297         return 1;
1298 }
1299
1300 // hud_add(self, form)
1301 int ObjectRef::l_hud_add(lua_State *L)
1302 {
1303         NO_MAP_LOCK_REQUIRED;
1304         ObjectRef *ref = checkobject(L, 1);
1305         RemotePlayer *player = getplayer(ref);
1306         if (player == NULL)
1307                 return 0;
1308
1309         HudElement *elem = new HudElement;
1310         read_hud_element(L, elem);
1311
1312         u32 id = getServer(L)->hudAdd(player, elem);
1313         if (id == U32_MAX) {
1314                 delete elem;
1315                 return 0;
1316         }
1317
1318         lua_pushnumber(L, id);
1319         return 1;
1320 }
1321
1322 // hud_remove(self, id)
1323 int ObjectRef::l_hud_remove(lua_State *L)
1324 {
1325         NO_MAP_LOCK_REQUIRED;
1326         ObjectRef *ref = checkobject(L, 1);
1327         RemotePlayer *player = getplayer(ref);
1328         if (player == NULL)
1329                 return 0;
1330
1331         u32 id = -1;
1332         if (!lua_isnil(L, 2))
1333                 id = lua_tonumber(L, 2);
1334
1335         if (!getServer(L)->hudRemove(player, id))
1336                 return 0;
1337
1338         lua_pushboolean(L, true);
1339         return 1;
1340 }
1341
1342 // hud_change(self, id, stat, data)
1343 int ObjectRef::l_hud_change(lua_State *L)
1344 {
1345         NO_MAP_LOCK_REQUIRED;
1346         ObjectRef *ref = checkobject(L, 1);
1347         RemotePlayer *player = getplayer(ref);
1348         if (player == NULL)
1349                 return 0;
1350
1351         u32 id = lua_isnumber(L, 2) ? lua_tonumber(L, 2) : -1;
1352
1353         HudElement *e = player->getHud(id);
1354         if (!e)
1355                 return 0;
1356
1357         void *value = NULL;
1358         HudElementStat stat = read_hud_change(L, e, &value);
1359
1360         getServer(L)->hudChange(player, id, stat, value);
1361
1362         lua_pushboolean(L, true);
1363         return 1;
1364 }
1365
1366 // hud_get(self, id)
1367 int ObjectRef::l_hud_get(lua_State *L)
1368 {
1369         NO_MAP_LOCK_REQUIRED;
1370         ObjectRef *ref = checkobject(L, 1);
1371         RemotePlayer *player = getplayer(ref);
1372         if (player == NULL)
1373                 return 0;
1374
1375         u32 id = lua_tonumber(L, -1);
1376
1377         HudElement *e = player->getHud(id);
1378         if (!e)
1379                 return 0;
1380         push_hud_element(L, e);
1381         return 1;
1382 }
1383
1384 // hud_set_flags(self, flags)
1385 int ObjectRef::l_hud_set_flags(lua_State *L)
1386 {
1387         NO_MAP_LOCK_REQUIRED;
1388         ObjectRef *ref = checkobject(L, 1);
1389         RemotePlayer *player = getplayer(ref);
1390         if (player == NULL)
1391                 return 0;
1392
1393         u32 flags = 0;
1394         u32 mask  = 0;
1395         bool flag;
1396
1397         const EnumString *esp = es_HudBuiltinElement;
1398         for (int i = 0; esp[i].str; i++) {
1399                 if (getboolfield(L, 2, esp[i].str, flag)) {
1400                         flags |= esp[i].num * flag;
1401                         mask  |= esp[i].num;
1402                 }
1403         }
1404         if (!getServer(L)->hudSetFlags(player, flags, mask))
1405                 return 0;
1406
1407         lua_pushboolean(L, true);
1408         return 1;
1409 }
1410
1411 int ObjectRef::l_hud_get_flags(lua_State *L)
1412 {
1413         NO_MAP_LOCK_REQUIRED;
1414         ObjectRef *ref = checkobject(L, 1);
1415         RemotePlayer *player = getplayer(ref);
1416         if (player == NULL)
1417                 return 0;
1418
1419         lua_newtable(L);
1420         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
1421         lua_setfield(L, -2, "hotbar");
1422         lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
1423         lua_setfield(L, -2, "healthbar");
1424         lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
1425         lua_setfield(L, -2, "crosshair");
1426         lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
1427         lua_setfield(L, -2, "wielditem");
1428         lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
1429         lua_setfield(L, -2, "breathbar");
1430         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
1431         lua_setfield(L, -2, "minimap");
1432         lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
1433         lua_setfield(L, -2, "minimap_radar");
1434
1435         return 1;
1436 }
1437
1438 // hud_set_hotbar_itemcount(self, hotbar_itemcount)
1439 int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
1440 {
1441         NO_MAP_LOCK_REQUIRED;
1442         ObjectRef *ref = checkobject(L, 1);
1443         RemotePlayer *player = getplayer(ref);
1444         if (player == NULL)
1445                 return 0;
1446
1447         s32 hotbar_itemcount = lua_tonumber(L, 2);
1448
1449         if (!getServer(L)->hudSetHotbarItemcount(player, hotbar_itemcount))
1450                 return 0;
1451
1452         lua_pushboolean(L, true);
1453         return 1;
1454 }
1455
1456 // hud_get_hotbar_itemcount(self)
1457 int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
1458 {
1459         NO_MAP_LOCK_REQUIRED;
1460         ObjectRef *ref = checkobject(L, 1);
1461         RemotePlayer *player = getplayer(ref);
1462         if (player == NULL)
1463                 return 0;
1464
1465         s32 hotbar_itemcount = getServer(L)->hudGetHotbarItemcount(player);
1466
1467         lua_pushnumber(L, hotbar_itemcount);
1468         return 1;
1469 }
1470
1471 // hud_set_hotbar_image(self, name)
1472 int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
1473 {
1474         NO_MAP_LOCK_REQUIRED;
1475         ObjectRef *ref = checkobject(L, 1);
1476         RemotePlayer *player = getplayer(ref);
1477         if (player == NULL)
1478                 return 0;
1479
1480         std::string name = lua_tostring(L, 2);
1481
1482         getServer(L)->hudSetHotbarImage(player, name);
1483         return 1;
1484 }
1485
1486 // hud_get_hotbar_image(self)
1487 int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
1488 {
1489         NO_MAP_LOCK_REQUIRED;
1490         ObjectRef *ref = checkobject(L, 1);
1491         RemotePlayer *player = getplayer(ref);
1492         if (player == NULL)
1493                 return 0;
1494
1495         std::string name = getServer(L)->hudGetHotbarImage(player);
1496         lua_pushlstring(L, name.c_str(), name.size());
1497         return 1;
1498 }
1499
1500 // hud_set_hotbar_selected_image(self, name)
1501 int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
1502 {
1503         NO_MAP_LOCK_REQUIRED;
1504         ObjectRef *ref = checkobject(L, 1);
1505         RemotePlayer *player = getplayer(ref);
1506         if (player == NULL)
1507                 return 0;
1508
1509         std::string name = lua_tostring(L, 2);
1510
1511         getServer(L)->hudSetHotbarSelectedImage(player, name);
1512         return 1;
1513 }
1514
1515 // hud_get_hotbar_selected_image(self)
1516 int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
1517 {
1518         NO_MAP_LOCK_REQUIRED;
1519         ObjectRef *ref = checkobject(L, 1);
1520         RemotePlayer *player = getplayer(ref);
1521         if (player == NULL)
1522                 return 0;
1523
1524         const std::string &name = getServer(L)->hudGetHotbarSelectedImage(player);
1525         lua_pushlstring(L, name.c_str(), name.size());
1526         return 1;
1527 }
1528
1529 // set_sky(self, bgcolor, type, list, clouds = true)
1530 int ObjectRef::l_set_sky(lua_State *L)
1531 {
1532         NO_MAP_LOCK_REQUIRED;
1533         ObjectRef *ref = checkobject(L, 1);
1534         RemotePlayer *player = getplayer(ref);
1535         if (player == NULL)
1536                 return 0;
1537
1538         video::SColor bgcolor(255,255,255,255);
1539         read_color(L, 2, &bgcolor);
1540
1541         std::string type = luaL_checkstring(L, 3);
1542
1543         std::vector<std::string> params;
1544         if (lua_istable(L, 4)) {
1545                 lua_pushnil(L);
1546                 while (lua_next(L, 4) != 0) {
1547                         // key at index -2 and value at index -1
1548                         if (lua_isstring(L, -1))
1549                                 params.emplace_back(lua_tostring(L, -1));
1550                         else
1551                                 params.emplace_back("");
1552                         // removes value, keeps key for next iteration
1553                         lua_pop(L, 1);
1554                 }
1555         }
1556
1557         if (type == "skybox" && params.size() != 6)
1558                 throw LuaError("skybox expects 6 textures");
1559
1560         bool clouds = true;
1561         if (lua_isboolean(L, 5))
1562                 clouds = lua_toboolean(L, 5);
1563
1564         if (!getServer(L)->setSky(player, bgcolor, type, params, clouds))
1565                 return 0;
1566
1567         lua_pushboolean(L, true);
1568         return 1;
1569 }
1570
1571 // get_sky(self)
1572 int ObjectRef::l_get_sky(lua_State *L)
1573 {
1574         NO_MAP_LOCK_REQUIRED;
1575         ObjectRef *ref = checkobject(L, 1);
1576         RemotePlayer *player = getplayer(ref);
1577         if (player == NULL)
1578                 return 0;
1579         video::SColor bgcolor(255, 255, 255, 255);
1580         std::string type;
1581         std::vector<std::string> params;
1582         bool clouds;
1583
1584         player->getSky(&bgcolor, &type, &params, &clouds);
1585         type = type.empty() ? "regular" : type;
1586
1587         push_ARGB8(L, bgcolor);
1588         lua_pushlstring(L, type.c_str(), type.size());
1589         lua_newtable(L);
1590         s16 i = 1;
1591         for (const std::string &param : params) {
1592                 lua_pushlstring(L, param.c_str(), param.size());
1593                 lua_rawseti(L, -2, i);
1594                 i++;
1595         }
1596         lua_pushboolean(L, clouds);
1597         return 4;
1598 }
1599
1600 // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=})
1601 int ObjectRef::l_set_clouds(lua_State *L)
1602 {
1603         NO_MAP_LOCK_REQUIRED;
1604         ObjectRef *ref = checkobject(L, 1);
1605         RemotePlayer *player = getplayer(ref);
1606         if (!player)
1607                 return 0;
1608         if (!lua_istable(L, 2))
1609                 return 0;
1610
1611         CloudParams cloud_params = player->getCloudParams();
1612
1613         cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
1614
1615         lua_getfield(L, 2, "color");
1616         if (!lua_isnil(L, -1))
1617                 read_color(L, -1, &cloud_params.color_bright);
1618         lua_pop(L, 1);
1619         lua_getfield(L, 2, "ambient");
1620         if (!lua_isnil(L, -1))
1621                 read_color(L, -1, &cloud_params.color_ambient);
1622         lua_pop(L, 1);
1623
1624         cloud_params.height    = getfloatfield_default(L, 2, "height",    cloud_params.height   );
1625         cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
1626
1627         lua_getfield(L, 2, "speed");
1628         if (lua_istable(L, -1)) {
1629                 v2f new_speed;
1630                 new_speed.X = getfloatfield_default(L, -1, "x", 0);
1631                 new_speed.Y = getfloatfield_default(L, -1, "z", 0);
1632                 cloud_params.speed = new_speed;
1633         }
1634         lua_pop(L, 1);
1635
1636         if (!getServer(L)->setClouds(player, cloud_params.density,
1637                         cloud_params.color_bright, cloud_params.color_ambient,
1638                         cloud_params.height, cloud_params.thickness,
1639                         cloud_params.speed))
1640                 return 0;
1641
1642         player->setCloudParams(cloud_params);
1643
1644         lua_pushboolean(L, true);
1645         return 1;
1646 }
1647
1648 int ObjectRef::l_get_clouds(lua_State *L)
1649 {
1650         NO_MAP_LOCK_REQUIRED;
1651         ObjectRef *ref = checkobject(L, 1);
1652         RemotePlayer *player = getplayer(ref);
1653         if (!player)
1654                 return 0;
1655         const CloudParams &cloud_params = player->getCloudParams();
1656
1657         lua_newtable(L);
1658         lua_pushnumber(L, cloud_params.density);
1659         lua_setfield(L, -2, "density");
1660         push_ARGB8(L, cloud_params.color_bright);
1661         lua_setfield(L, -2, "color");
1662         push_ARGB8(L, cloud_params.color_ambient);
1663         lua_setfield(L, -2, "ambient");
1664         lua_pushnumber(L, cloud_params.height);
1665         lua_setfield(L, -2, "height");
1666         lua_pushnumber(L, cloud_params.thickness);
1667         lua_setfield(L, -2, "thickness");
1668         lua_newtable(L);
1669         lua_pushnumber(L, cloud_params.speed.X);
1670         lua_setfield(L, -2, "x");
1671         lua_pushnumber(L, cloud_params.speed.Y);
1672         lua_setfield(L, -2, "y");
1673         lua_setfield(L, -2, "speed");
1674
1675         return 1;
1676 }
1677
1678
1679 // override_day_night_ratio(self, brightness=0...1)
1680 int ObjectRef::l_override_day_night_ratio(lua_State *L)
1681 {
1682         NO_MAP_LOCK_REQUIRED;
1683         ObjectRef *ref = checkobject(L, 1);
1684         RemotePlayer *player = getplayer(ref);
1685         if (player == NULL)
1686                 return 0;
1687
1688         bool do_override = false;
1689         float ratio = 0.0f;
1690         if (!lua_isnil(L, 2)) {
1691                 do_override = true;
1692                 ratio = luaL_checknumber(L, 2);
1693         }
1694
1695         if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio))
1696                 return 0;
1697
1698         lua_pushboolean(L, true);
1699         return 1;
1700 }
1701
1702 // get_day_night_ratio(self)
1703 int ObjectRef::l_get_day_night_ratio(lua_State *L)
1704 {
1705         NO_MAP_LOCK_REQUIRED;
1706         ObjectRef *ref = checkobject(L, 1);
1707         RemotePlayer *player = getplayer(ref);
1708         if (player == NULL)
1709                 return 0;
1710
1711         bool do_override;
1712         float ratio;
1713         player->getDayNightRatio(&do_override, &ratio);
1714
1715         if (do_override)
1716                 lua_pushnumber(L, ratio);
1717         else
1718                 lua_pushnil(L);
1719
1720         return 1;
1721 }
1722
1723 ObjectRef::ObjectRef(ServerActiveObject *object):
1724         m_object(object)
1725 {
1726         //infostream<<"ObjectRef created for id="<<m_object->getId()<<std::endl;
1727 }
1728
1729 // Creates an ObjectRef and leaves it on top of stack
1730 // Not callable from Lua; all references are created on the C side.
1731 void ObjectRef::create(lua_State *L, ServerActiveObject *object)
1732 {
1733         ObjectRef *o = new ObjectRef(object);
1734         //infostream<<"ObjectRef::create: o="<<o<<std::endl;
1735         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
1736         luaL_getmetatable(L, className);
1737         lua_setmetatable(L, -2);
1738 }
1739
1740 void ObjectRef::set_null(lua_State *L)
1741 {
1742         ObjectRef *o = checkobject(L, -1);
1743         o->m_object = NULL;
1744 }
1745
1746 void ObjectRef::Register(lua_State *L)
1747 {
1748         lua_newtable(L);
1749         int methodtable = lua_gettop(L);
1750         luaL_newmetatable(L, className);
1751         int metatable = lua_gettop(L);
1752
1753         lua_pushliteral(L, "__metatable");
1754         lua_pushvalue(L, methodtable);
1755         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
1756
1757         lua_pushliteral(L, "__index");
1758         lua_pushvalue(L, methodtable);
1759         lua_settable(L, metatable);
1760
1761         lua_pushliteral(L, "__gc");
1762         lua_pushcfunction(L, gc_object);
1763         lua_settable(L, metatable);
1764
1765         lua_pop(L, 1);  // drop metatable
1766
1767         luaL_openlib(L, 0, methods, 0);  // fill methodtable
1768         lua_pop(L, 1);  // drop methodtable
1769
1770         // Cannot be created from Lua
1771         //lua_register(L, className, create_object);
1772 }
1773
1774 const char ObjectRef::className[] = "ObjectRef";
1775 const luaL_Reg ObjectRef::methods[] = {
1776         // ServerActiveObject
1777         luamethod(ObjectRef, remove),
1778         luamethod_aliased(ObjectRef, get_pos, getpos),
1779         luamethod_aliased(ObjectRef, set_pos, setpos),
1780         luamethod_aliased(ObjectRef, move_to, moveto),
1781         luamethod(ObjectRef, punch),
1782         luamethod(ObjectRef, right_click),
1783         luamethod(ObjectRef, set_hp),
1784         luamethod(ObjectRef, get_hp),
1785         luamethod(ObjectRef, get_inventory),
1786         luamethod(ObjectRef, get_wield_list),
1787         luamethod(ObjectRef, get_wield_index),
1788         luamethod(ObjectRef, get_wielded_item),
1789         luamethod(ObjectRef, set_wielded_item),
1790         luamethod(ObjectRef, set_armor_groups),
1791         luamethod(ObjectRef, get_armor_groups),
1792         luamethod(ObjectRef, set_animation),
1793         luamethod(ObjectRef, get_animation),
1794         luamethod(ObjectRef, set_animation_frame_speed),
1795         luamethod(ObjectRef, set_bone_position),
1796         luamethod(ObjectRef, get_bone_position),
1797         luamethod(ObjectRef, set_attach),
1798         luamethod(ObjectRef, get_attach),
1799         luamethod(ObjectRef, set_detach),
1800         luamethod(ObjectRef, set_properties),
1801         luamethod(ObjectRef, get_properties),
1802         luamethod(ObjectRef, set_nametag_attributes),
1803         luamethod(ObjectRef, get_nametag_attributes),
1804         // LuaEntitySAO-only
1805         luamethod_aliased(ObjectRef, set_velocity, setvelocity),
1806         luamethod_aliased(ObjectRef, get_velocity, getvelocity),
1807         luamethod_aliased(ObjectRef, set_acceleration, setacceleration),
1808         luamethod_aliased(ObjectRef, get_acceleration, getacceleration),
1809         luamethod_aliased(ObjectRef, set_yaw, setyaw),
1810         luamethod_aliased(ObjectRef, get_yaw, getyaw),
1811         luamethod_aliased(ObjectRef, set_texture_mod, settexturemod),
1812         luamethod_aliased(ObjectRef, set_sprite, setsprite),
1813         luamethod(ObjectRef, get_entity_name),
1814         luamethod(ObjectRef, get_luaentity),
1815         // Player-only
1816         luamethod(ObjectRef, is_player),
1817         luamethod(ObjectRef, is_player_connected),
1818         luamethod(ObjectRef, get_player_name),
1819         luamethod(ObjectRef, get_player_velocity),
1820         luamethod(ObjectRef, get_look_dir),
1821         luamethod(ObjectRef, get_look_pitch),
1822         luamethod(ObjectRef, get_look_yaw),
1823         luamethod(ObjectRef, get_look_vertical),
1824         luamethod(ObjectRef, get_look_horizontal),
1825         luamethod(ObjectRef, set_look_horizontal),
1826         luamethod(ObjectRef, set_look_vertical),
1827         luamethod(ObjectRef, set_look_yaw),
1828         luamethod(ObjectRef, set_look_pitch),
1829         luamethod(ObjectRef, get_breath),
1830         luamethod(ObjectRef, set_breath),
1831         luamethod(ObjectRef, get_attribute),
1832         luamethod(ObjectRef, set_attribute),
1833         luamethod(ObjectRef, set_inventory_formspec),
1834         luamethod(ObjectRef, get_inventory_formspec),
1835         luamethod(ObjectRef, get_player_control),
1836         luamethod(ObjectRef, get_player_control_bits),
1837         luamethod(ObjectRef, set_physics_override),
1838         luamethod(ObjectRef, get_physics_override),
1839         luamethod(ObjectRef, hud_add),
1840         luamethod(ObjectRef, hud_remove),
1841         luamethod(ObjectRef, hud_change),
1842         luamethod(ObjectRef, hud_get),
1843         luamethod(ObjectRef, hud_set_flags),
1844         luamethod(ObjectRef, hud_get_flags),
1845         luamethod(ObjectRef, hud_set_hotbar_itemcount),
1846         luamethod(ObjectRef, hud_get_hotbar_itemcount),
1847         luamethod(ObjectRef, hud_set_hotbar_image),
1848         luamethod(ObjectRef, hud_get_hotbar_image),
1849         luamethod(ObjectRef, hud_set_hotbar_selected_image),
1850         luamethod(ObjectRef, hud_get_hotbar_selected_image),
1851         luamethod(ObjectRef, set_sky),
1852         luamethod(ObjectRef, get_sky),
1853         luamethod(ObjectRef, set_clouds),
1854         luamethod(ObjectRef, get_clouds),
1855         luamethod(ObjectRef, override_day_night_ratio),
1856         luamethod(ObjectRef, get_day_night_ratio),
1857         luamethod(ObjectRef, set_local_animation),
1858         luamethod(ObjectRef, get_local_animation),
1859         luamethod(ObjectRef, set_eye_offset),
1860         luamethod(ObjectRef, get_eye_offset),
1861         {0,0}
1862 };