From ab433775777c4f5055bcf4d2a1cffc506c4f9961 Mon Sep 17 00:00:00 2001 From: sapier Date: Sat, 25 May 2013 00:51:02 +0200 Subject: Move scriptapi to separate folder (by sapier) On the lua side, notably minetest.env:() should now be replaced by minetest.(). The old way is and will stay supported for a long time. Also: Update and clean up lua_api.txt (by celeron55) Move EnvRef to lua and remove add_rat and add_firefly (by kahrl) Add separate src/util/CMakeLists.txt, other minor fixes (by kahrl) --- src/script/lua_api/l_object.cpp | 1095 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1095 insertions(+) create mode 100644 src/script/lua_api/l_object.cpp (limited to 'src/script/lua_api/l_object.cpp') diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp new file mode 100644 index 000000000..6dec3db85 --- /dev/null +++ b/src/script/lua_api/l_object.cpp @@ -0,0 +1,1095 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "cpp_api/scriptapi.h" +#include "common/c_converter.h" +#include "common/c_content.h" +#include "lua_api/l_object.h" +#include "common/c_internal.h" +#include "lua_api/l_inventory.h" +#include "lua_api/l_item.h" +#include "log.h" +#include "tool.h" +#include "serverobject.h" +#include "content_object.h" +#include "content_sao.h" +#include "server.h" +#include "hud.h" + + +struct EnumString es_HudElementType[] = +{ + {HUD_ELEM_IMAGE, "image"}, + {HUD_ELEM_TEXT, "text"}, + {HUD_ELEM_STATBAR, "statbar"}, + {HUD_ELEM_INVENTORY, "inventory"}, +{0, NULL}, +}; + +struct EnumString es_HudElementStat[] = +{ + {HUD_STAT_POS, "pos"}, + {HUD_STAT_NAME, "name"}, + {HUD_STAT_SCALE, "scale"}, + {HUD_STAT_TEXT, "text"}, + {HUD_STAT_NUMBER, "number"}, + {HUD_STAT_ITEM, "item"}, + {HUD_STAT_DIR, "direction"}, + {HUD_STAT_ALIGN, "alignment"}, + {HUD_STAT_OFFSET, "offset"}, + {0, NULL}, +}; + +struct EnumString es_HudBuiltinElement[] = +{ + {HUD_FLAG_HOTBAR_VISIBLE, "hotbar"}, + {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, + {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, + {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, + {0, NULL}, +}; + +/* + ObjectRef +*/ + + +ObjectRef* ObjectRef::checkobject(lua_State *L, int narg) +{ + luaL_checktype(L, narg, LUA_TUSERDATA); + void *ud = luaL_checkudata(L, narg, className); + if(!ud) luaL_typerror(L, narg, className); + return *(ObjectRef**)ud; // unbox pointer +} + +ServerActiveObject* ObjectRef::getobject(ObjectRef *ref) +{ + ServerActiveObject *co = ref->m_object; + return co; +} + +LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref) +{ + ServerActiveObject *obj = getobject(ref); + if(obj == NULL) + return NULL; + if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY) + return NULL; + return (LuaEntitySAO*)obj; +} + +PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref) +{ + ServerActiveObject *obj = getobject(ref); + if(obj == NULL) + return NULL; + if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER) + return NULL; + return (PlayerSAO*)obj; +} + +Player* ObjectRef::getplayer(ObjectRef *ref) +{ + PlayerSAO *playersao = getplayersao(ref); + if(playersao == NULL) + return NULL; + return playersao->getPlayer(); +} + +// Exported functions + +// garbage collector +int ObjectRef::gc_object(lua_State *L) { + ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); + //infostream<<"ObjectRef::gc_object: o="<setPos(pos); + return 0; +} + +// moveto(self, pos, continuous=false) +int ObjectRef::l_moveto(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + //LuaEntitySAO *co = getluaobject(ref); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); + // continuous + bool continuous = lua_toboolean(L, 3); + // Do it + co->moveTo(pos, continuous); + return 0; +} + +// punch(self, puncher, time_from_last_punch, tool_capabilities, dir) +int ObjectRef::l_punch(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ObjectRef *puncher_ref = checkobject(L, 2); + ServerActiveObject *co = getobject(ref); + ServerActiveObject *puncher = getobject(puncher_ref); + if(co == NULL) return 0; + if(puncher == NULL) return 0; + v3f dir; + if(lua_type(L, 5) != LUA_TTABLE) + dir = co->getBasePosition() - puncher->getBasePosition(); + else + dir = read_v3f(L, 5); + float time_from_last_punch = 1000000; + if(lua_isnumber(L, 3)) + time_from_last_punch = lua_tonumber(L, 3); + ToolCapabilities toolcap = read_tool_capabilities(L, 4); + dir.normalize(); + // Do it + co->punch(dir, &toolcap, puncher, time_from_last_punch); + return 0; +} + +// right_click(self, clicker); clicker = an another ObjectRef +int ObjectRef::l_right_click(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ObjectRef *ref2 = checkobject(L, 2); + ServerActiveObject *co = getobject(ref); + ServerActiveObject *co2 = getobject(ref2); + if(co == NULL) return 0; + if(co2 == NULL) return 0; + // Do it + co->rightClick(co2); + return 0; +} + +// set_hp(self, hp) +// hp = number of hitpoints (2 * number of hearts) +// returns: nil +int ObjectRef::l_set_hp(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + luaL_checknumber(L, 2); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + int hp = lua_tonumber(L, 2); + /*infostream<<"ObjectRef::l_set_hp(): id="<getId() + <<" hp="<setHP(hp); + // Return + return 0; +} + +// get_hp(self) +// returns: number of hitpoints (2 * number of hearts) +// 0 if not applicable to this type of object +int ObjectRef::l_get_hp(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL){ + // Default hp is 1 + lua_pushnumber(L, 1); + return 1; + } + int hp = co->getHP(); + /*infostream<<"ObjectRef::l_get_hp(): id="<getId() + <<" hp="<getInventoryLocation(); + if(STACK_TO_SERVER(L)->getInventory(loc) != NULL) + InvRef::create(L, loc); + else + lua_pushnil(L); // An object may have no inventory (nil) + return 1; +} + +// get_wield_list(self) +int ObjectRef::l_get_wield_list(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + lua_pushstring(L, co->getWieldList().c_str()); + return 1; +} + +// get_wield_index(self) +int ObjectRef::l_get_wield_index(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + lua_pushinteger(L, co->getWieldIndex() + 1); + return 1; +} + +// get_wielded_item(self) +int ObjectRef::l_get_wielded_item(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL){ + // Empty ItemStack + LuaItemStack::create(L, ItemStack()); + return 1; + } + // Do it + LuaItemStack::create(L, co->getWieldedItem()); + return 1; +} + +// set_wielded_item(self, itemstack or itemstring or table or nil) +int ObjectRef::l_set_wielded_item(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + ItemStack item = read_item(L, 2,STACK_TO_SERVER(L)); + bool success = co->setWieldedItem(item); + lua_pushboolean(L, success); + return 1; +} + +// set_armor_groups(self, groups) +int ObjectRef::l_set_armor_groups(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + ItemGroupList groups; + read_groups(L, 2, groups); + co->setArmorGroups(groups); + return 0; +} + +// set_physics_override(self, physics_override_speed, physics_override_jump, physics_override_gravity) +int ObjectRef::l_set_physics_override(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + PlayerSAO *co = (PlayerSAO *) getobject(ref); + if(co == NULL) return 0; + // Do it + if(!lua_isnil(L, 2)){ + co->m_physics_override_speed = lua_tonumber(L, 2); + co->m_physics_override_sent = false; + } + if(!lua_isnil(L, 3)){ + co->m_physics_override_jump = lua_tonumber(L, 3); + co->m_physics_override_sent = false; + } + if(!lua_isnil(L, 4)){ + co->m_physics_override_gravity = lua_tonumber(L, 4); + co->m_physics_override_sent = false; + } + return 0; +} + +// set_animation(self, frame_range, frame_speed, frame_blend) +int ObjectRef::l_set_animation(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + v2f frames = v2f(1, 1); + if(!lua_isnil(L, 2)) + frames = read_v2f(L, 2); + float frame_speed = 15; + if(!lua_isnil(L, 3)) + frame_speed = lua_tonumber(L, 3); + float frame_blend = 0; + if(!lua_isnil(L, 4)) + frame_blend = lua_tonumber(L, 4); + co->setAnimation(frames, frame_speed, frame_blend); + return 0; +} + +// set_bone_position(self, std::string bone, v3f position, v3f rotation) +int ObjectRef::l_set_bone_position(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + std::string bone = ""; + if(!lua_isnil(L, 2)) + bone = lua_tostring(L, 2); + v3f position = v3f(0, 0, 0); + if(!lua_isnil(L, 3)) + position = read_v3f(L, 3); + v3f rotation = v3f(0, 0, 0); + if(!lua_isnil(L, 4)) + rotation = read_v3f(L, 4); + co->setBonePosition(bone, position, rotation); + return 0; +} + +// set_attach(self, parent, bone, position, rotation) +int ObjectRef::l_set_attach(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ObjectRef *parent_ref = checkobject(L, 2); + ServerActiveObject *co = getobject(ref); + ServerActiveObject *parent = getobject(parent_ref); + if(co == NULL) return 0; + if(parent == NULL) return 0; + // Do it + std::string bone = ""; + if(!lua_isnil(L, 3)) + bone = lua_tostring(L, 3); + v3f position = v3f(0, 0, 0); + if(!lua_isnil(L, 4)) + position = read_v3f(L, 4); + v3f rotation = v3f(0, 0, 0); + if(!lua_isnil(L, 5)) + rotation = read_v3f(L, 5); + co->setAttachment(parent->getId(), bone, position, rotation); + return 0; +} + +// set_detach(self) +int ObjectRef::l_set_detach(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0)); + return 0; +} + +// set_properties(self, properties) +int ObjectRef::l_set_properties(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + ObjectProperties *prop = co->accessObjectProperties(); + if(!prop) + return 0; + read_object_properties(L, 2, prop); + co->notifyObjectPropertiesModified(); + return 0; +} + +/* LuaEntitySAO-only */ + +// setvelocity(self, {x=num, y=num, z=num}) +int ObjectRef::l_setvelocity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + v3f pos = checkFloatPos(L, 2); + // Do it + co->setVelocity(pos); + return 0; +} + +// getvelocity(self) +int ObjectRef::l_getvelocity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v3f v = co->getVelocity(); + pushFloatPos(L, v); + return 1; +} + +// setacceleration(self, {x=num, y=num, z=num}) +int ObjectRef::l_setacceleration(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); + // Do it + co->setAcceleration(pos); + return 0; +} + +// getacceleration(self) +int ObjectRef::l_getacceleration(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v3f v = co->getAcceleration(); + pushFloatPos(L, v); + return 1; +} + +// setyaw(self, radians) +int ObjectRef::l_setyaw(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + float yaw = luaL_checknumber(L, 2) * core::RADTODEG; + // Do it + co->setYaw(yaw); + return 0; +} + +// getyaw(self) +int ObjectRef::l_getyaw(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + float yaw = co->getYaw() * core::DEGTORAD; + lua_pushnumber(L, yaw); + return 1; +} + +// settexturemod(self, mod) +int ObjectRef::l_settexturemod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + std::string mod = luaL_checkstring(L, 2); + co->setTextureMod(mod); + return 0; +} + +// setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2, +// select_horiz_by_yawpitch=false) +int ObjectRef::l_setsprite(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v2s16 p(0,0); + if(!lua_isnil(L, 2)) + p = read_v2s16(L, 2); + int num_frames = 1; + if(!lua_isnil(L, 3)) + num_frames = lua_tonumber(L, 3); + float framelength = 0.2; + if(!lua_isnil(L, 4)) + framelength = lua_tonumber(L, 4); + bool select_horiz_by_yawpitch = false; + if(!lua_isnil(L, 5)) + select_horiz_by_yawpitch = lua_toboolean(L, 5); + co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch); + return 0; +} + +// DEPRECATED +// get_entity_name(self) +int ObjectRef::l_get_entity_name(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + std::string name = co->getName(); + lua_pushstring(L, name.c_str()); + return 1; +} + +// get_luaentity(self) +int ObjectRef::l_get_luaentity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + luaentity_get(L, co->getId()); + return 1; +} + +/* Player-only */ + +// is_player(self) +int ObjectRef::l_is_player(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + lua_pushboolean(L, (player != NULL)); + return 1; +} + +// get_player_name(self) +int ObjectRef::l_get_player_name(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL){ + lua_pushlstring(L, "", 0); + return 1; + } + // Do it + lua_pushstring(L, player->getName()); + return 1; +} + +// get_look_dir(self) +int ObjectRef::l_get_look_dir(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL) return 0; + // Do it + float pitch = player->getRadPitch(); + float yaw = player->getRadYaw(); + v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw)); + push_v3f(L, v); + return 1; +} + +// get_look_pitch(self) +int ObjectRef::l_get_look_pitch(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL) return 0; + // Do it + lua_pushnumber(L, player->getRadPitch()); + return 1; +} + +// get_look_yaw(self) +int ObjectRef::l_get_look_yaw(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL) return 0; + // Do it + lua_pushnumber(L, player->getRadYaw()); + return 1; +} + +// set_look_pitch(self, radians) +int ObjectRef::l_set_look_pitch(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + PlayerSAO* co = getplayersao(ref); + if(co == NULL) return 0; + float pitch = luaL_checknumber(L, 2) * core::RADTODEG; + // Do it + co->setPitch(pitch); + return 1; +} + +// set_look_yaw(self, radians) +int ObjectRef::l_set_look_yaw(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + PlayerSAO* co = getplayersao(ref); + if(co == NULL) return 0; + float yaw = luaL_checknumber(L, 2) * core::RADTODEG; + // Do it + co->setYaw(yaw); + return 1; +} + +// set_inventory_formspec(self, formspec) +int ObjectRef::l_set_inventory_formspec(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL) return 0; + std::string formspec = luaL_checkstring(L, 2); + + player->inventory_formspec = formspec; + STACK_TO_SERVER(L)->reportInventoryFormspecModified(player->getName()); + lua_pushboolean(L, true); + return 1; +} + +// get_inventory_formspec(self) -> formspec +int ObjectRef::l_get_inventory_formspec(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL) return 0; + + std::string formspec = player->inventory_formspec; + lua_pushlstring(L, formspec.c_str(), formspec.size()); + return 1; +} + +// get_player_control(self) +int ObjectRef::l_get_player_control(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL){ + lua_pushlstring(L, "", 0); + return 1; + } + // Do it + PlayerControl control = player->getPlayerControl(); + lua_newtable(L); + lua_pushboolean(L, control.up); + lua_setfield(L, -2, "up"); + lua_pushboolean(L, control.down); + lua_setfield(L, -2, "down"); + lua_pushboolean(L, control.left); + lua_setfield(L, -2, "left"); + lua_pushboolean(L, control.right); + lua_setfield(L, -2, "right"); + lua_pushboolean(L, control.jump); + lua_setfield(L, -2, "jump"); + lua_pushboolean(L, control.aux1); + lua_setfield(L, -2, "aux1"); + lua_pushboolean(L, control.sneak); + lua_setfield(L, -2, "sneak"); + lua_pushboolean(L, control.LMB); + lua_setfield(L, -2, "LMB"); + lua_pushboolean(L, control.RMB); + lua_setfield(L, -2, "RMB"); + return 1; +} + +// get_player_control_bits(self) +int ObjectRef::l_get_player_control_bits(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if(player == NULL){ + lua_pushlstring(L, "", 0); + return 1; + } + // Do it + lua_pushnumber(L, player->keyPressed); + return 1; +} + +// hud_add(self, form) +int ObjectRef::l_hud_add(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + + HudElement *elem = new HudElement; + + elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", + es_HudElementType, HUD_ELEM_TEXT); + + lua_getfield(L, 2, "position"); + elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "scale"); + elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + elem->name = getstringfield_default(L, 2, "name", ""); + elem->text = getstringfield_default(L, 2, "text", ""); + elem->number = getintfield_default(L, 2, "number", 0); + elem->item = getintfield_default(L, 2, "item", 0); + elem->dir = getintfield_default(L, 2, "dir", 0); + + lua_getfield(L, 2, "alignment"); + elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "offset"); + elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + u32 id = STACK_TO_SERVER(L)->hudAdd(player, elem); + if (id == (u32)-1) { + delete elem; + return 0; + } + + lua_pushnumber(L, id); + return 1; +} + +// hud_remove(self, id) +int ObjectRef::l_hud_remove(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + + u32 id = -1; + if (!lua_isnil(L, 2)) + id = lua_tonumber(L, 2); + + if (!STACK_TO_SERVER(L)->hudRemove(player, id)) + return 0; + + lua_pushboolean(L, true); + return 1; +} + +// hud_change(self, id, stat, data) +int ObjectRef::l_hud_change(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + + u32 id = -1; + if (!lua_isnil(L, 2)) + id = lua_tonumber(L, 2); + + HudElementStat stat = (HudElementStat)getenumfield(L, 3, "stat", + es_HudElementStat, HUD_STAT_NUMBER); + + if (id >= player->hud.size()) + return 0; + + void *value = NULL; + HudElement *e = player->hud[id]; + if (!e) + return 0; + + switch (stat) { + case HUD_STAT_POS: + e->pos = read_v2f(L, 4); + value = &e->pos; + break; + case HUD_STAT_NAME: + e->name = lua_tostring(L, 4); + value = &e->name; + break; + case HUD_STAT_SCALE: + e->scale = read_v2f(L, 4); + value = &e->scale; + break; + case HUD_STAT_TEXT: + e->text = lua_tostring(L, 4); + value = &e->text; + break; + case HUD_STAT_NUMBER: + e->number = lua_tonumber(L, 4); + value = &e->number; + break; + case HUD_STAT_ITEM: + e->item = lua_tonumber(L, 4); + value = &e->item; + break; + case HUD_STAT_DIR: + e->dir = lua_tonumber(L, 4); + value = &e->dir; + case HUD_STAT_ALIGN: + e->align = read_v2f(L, 4); + value = &e->align; + case HUD_STAT_OFFSET: + e->offset = read_v2f(L, 4); + value = &e->offset; + } + + STACK_TO_SERVER(L)->hudChange(player, id, stat, value); + + lua_pushboolean(L, true); + return 1; +} + +// hud_get(self, id) +int ObjectRef::l_hud_get(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + + u32 id = lua_tonumber(L, -1); + if (id >= player->hud.size()) + return 0; + + HudElement *e = player->hud[id]; + if (!e) + return 0; + + lua_newtable(L); + + lua_pushstring(L, es_HudElementType[(u8)e->type].str); + lua_setfield(L, -2, "type"); + + push_v2f(L, e->pos); + lua_setfield(L, -2, "position"); + + lua_pushstring(L, e->name.c_str()); + lua_setfield(L, -2, "name"); + + push_v2f(L, e->scale); + lua_setfield(L, -2, "scale"); + + lua_pushstring(L, e->text.c_str()); + lua_setfield(L, -2, "text"); + + lua_pushnumber(L, e->number); + lua_setfield(L, -2, "number"); + + lua_pushnumber(L, e->item); + lua_setfield(L, -2, "item"); + + lua_pushnumber(L, e->dir); + lua_setfield(L, -2, "dir"); + + return 1; +} + +// hud_set_flags(self, flags) +int ObjectRef::l_hud_set_flags(lua_State *L) +{ + ObjectRef *ref = checkobject(L, 1); + Player *player = getplayer(ref); + if (player == NULL) + return 0; + + u32 flags = 0; + u32 mask = 0; + bool flag; + + const EnumString *esp = es_HudBuiltinElement; + for (int i = 0; esp[i].str; i++) { + if (getboolfield(L, 2, esp[i].str, flag)) { + flags |= esp[i].num * flag; + mask |= esp[i].num; + } + } + if (!STACK_TO_SERVER(L)->hudSetFlags(player, flags, mask)) + return 0; + + lua_pushboolean(L, true); + return 1; +} + +ObjectRef::ObjectRef(ServerActiveObject *object): + m_object(object) +{ + //infostream<<"ObjectRef created for id="<getId()<