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