#include "world.hpp" #include "pprint.hpp" static void tangible_getall(LuaStack &LS0, LuaSlot list, const util::IdVector &idv) { LuaVar tangibles, tan; LuaStack LS(LS0.state(), tangibles, tan); LS.rawget(tangibles, LuaRegistry, "tangibles"); assert(LS.istable(tangibles)); LS.set(list, LuaNewTable); int index = 1; for (int64_t id : idv) { LS.rawget(tan, tangibles, id); assert(LS.istable(tan)); LS.rawset(list, index++, tan); } LS.result(); } LuaDefine(tangible_animstate, "c") { LuaArg tanobj; LuaRet graphic, plane, x, y, z, facing; LuaStack LS(L, tanobj, graphic, plane, x, y, z, facing); World *w = World::fetch_global_pointer(L); Tangible *tan = w->tangible_get(LS, tanobj); const AnimStep &aqback = tan->anim_queue_.back(); LS.set(graphic, aqback.graphic()); LS.set(plane, aqback.plane()); LS.set(x, aqback.xyz().x); LS.set(y, aqback.xyz().y); LS.set(z, aqback.xyz().z); LS.set(facing, aqback.facing()); return LS.result(); } LuaDefine(tangible_animate, "c") { LuaArg tanobj, config; LuaStack LS(L, tanobj, config); World *w = World::fetch_global_pointer(L); Tangible *tan = w->tangible_get(LS, tanobj); int64_t id = w->alloc_id_predictable(); const AnimStep &prev = tan->anim_queue_.back(); AnimStep step; step.from_lua(L, config.index(), false, prev); if (step.action() == "") { luaL_error(L, "animation action must be specified"); } tan->anim_queue_.add(id, step); tan->update_plane_item(); return LS.result(); } LuaDefine(tangible_setclass, "c") { LuaArg tanobj, classname; LuaVar classtab, mt; LuaStack LS(L, tanobj, classname, classtab, mt); World *w = World::fetch_global_pointer(L); w->tangible_get(LS, tanobj); if (LS.classname(classname) != "") { LS.set(classtab, classname); } else { LS.getclass(classtab, classname); } LS.getmetatable(mt, tanobj); LS.rawset(mt, "__index", classtab); return LS.result(); } LuaDefine(tangible_getclass, "c") { LuaArg tanobj; LuaVar mt, classtab; LuaRet classname; LuaStack LS(L, tanobj, mt, classtab, classname); World *w = World::fetch_global_pointer(L); w->tangible_get(LS, tanobj); LS.getmetatable(mt, tanobj); LS.rawget(classtab, mt, "__index"); std::string name = LS.classname(classtab); if (name == "") { LS.set(classname, LuaNil); } else { LS.set(classname, name); } return LS.result(); } LuaDefine(tangible_delete, "c") { LuaArg tanobj; LuaStack LS(L, tanobj); World *w = World::fetch_global_pointer(L); Tangible *tan = w->tangible_get(LS, tanobj); assert(tan != nullptr); // this should be checked above. if (tan->is_an_actor()) { luaL_error(L, "Cannot delete a player using tangible.delete, use tangible.redirect instead."); return 0; } w->tangible_delete(tan->id()); return LS.result(); } LuaDefine(tangible_build, "c") { LuaArg config; LuaVar classname, classtab, mt; LuaRet database; LuaStack LS(L, config, classname, classtab, database, mt); LS.checktable(config); // Get the class of the new tangible. LS.rawget(classname, config, "class"); if (LS.isnil(classname)) { luaL_error(L, "must specify a class name"); } else if (LS.classname(classname) != "") { LS.set(classtab, classname); } else { LS.getclass(classtab, classname); } // Parse the initial animation step. AnimStep initstep, blank; initstep.from_lua(L, config.index(), true, blank); if (!initstep.has_xyz()) { luaL_error(L, "You must specify (X,Y,Z) for new tangible"); } if (!initstep.has_plane()) { luaL_error(L, "You must specify plane for new tangible"); } if (!initstep.has_graphic()) { luaL_error(L, "You must specify graphic for new tangible"); } // TODO: generate error if there's extra crap in the config table. World *w = World::fetch_global_pointer(L); int64_t new_id = w->alloc_id_predictable(); Tangible *tan = w->tangible_make(L, new_id, "nowhere", true); lua_replace(L, database.index()); // Update the class of the new tangible. LS.getmetatable(mt, database); LS.rawset(mt, "__index", classtab); // Update the animation queue and planemap of the new tangible. int64_t stepid = w->alloc_id_predictable(); tan->anim_queue_.add(stepid, initstep); tan->update_plane_item(); return LS.result(); } LuaDefine(tangible_get, "c") { LuaArg id; LuaVar tangibles; LuaRet database; LuaStack LS(L, id, tangibles, database); int64_t nid = LS.ckinteger(id); LS.rawget(tangibles, LuaRegistry, "tangibles"); LS.rawget(database, tangibles, id); if (!LS.istable(database)) { luaL_error(L, "Not a tangible ID: %d", nid); } return LS.result(); } LuaDefine(tangible_redirect, "c") { LuaArg actor1, actor2, bldz; LuaStack LS(L, actor1, actor2, bldz); World *w = World::fetch_global_pointer(L); bool bulldoze = LS.ckboolean(bldz); Tangible *tan1 = w->tangible_get(LS, actor1); if (!tan1->is_an_actor()) { luaL_error(L, "redirect source is not an actor"); } if (LS.isnil(actor2)) { w->redirects_[tan1->id()] = 0; } else { Tangible *tan2 = w->tangible_get(LS, actor2); tan2->configure_id_pool_for_actor(); w->redirects_[tan1->id()] = tan2->id(); } if (bulldoze) { w->tangible_delete(tan1->id()); } return LS.result(); } LuaDefine(tangible_id, "c") { LuaArg tanobj; LuaRet id; LuaStack LS(L, tanobj, id); int64_t tid = LS.tanid(tanobj); if (tid == 0) { luaL_error(L, "Not a tangible"); } LS.set(id, tid); return LS.result(); } LuaDefine(tangible_actor, "c") { LuaRet actor; LuaVar tangibles; LuaStack LS(L, tangibles, actor); World *w = World::fetch_global_pointer(L); LS.rawget(tangibles, LuaRegistry, "tangibles"); LS.rawget(actor, tangibles, w->lthread_actor_id_); return LS.result(); } LuaDefine(tangible_place, "c") { LuaRet place; LuaVar tangibles; LuaStack LS(L, tangibles, place); World *w = World::fetch_global_pointer(L); LS.rawget(tangibles, LuaRegistry, "tangibles"); LS.rawget(place, tangibles, w->lthread_place_id_); return LS.result(); } LuaDefine(tangible_near, "c") { LuaArg ltan, lradius, lomit_nowhere, lomit_self; LuaRet list; LuaStack LS(L, ltan, lradius, lomit_nowhere, lomit_self, list); World *w = World::fetch_global_pointer(L); Tangible *tan = w->tangible_get(LS, ltan); double radius = LS.cknumber(lradius); bool omit_nowhere = LS.ckboolean(lomit_nowhere); bool omit_self = LS.ckboolean(lomit_self); const AnimStep &aqback = tan->anim_queue_.back(); util::IdVector idv = w->plane_map_.scan_radius(aqback.plane(), aqback.xyz().x, aqback.xyz().y, radius, omit_nowhere, tan->id(), omit_self); tangible_getall(LS, list, idv); return LS.result(); } LuaDefine(tangible_scan, "c") { LuaArg lplane, lx, ly, lradius, lomit_nowhere; LuaRet list; LuaStack LS(L, lplane, lx, ly, lradius, lomit_nowhere, list); World *w = World::fetch_global_pointer(L); std::string plane = LS.ckstring(lplane); double x = LS.cknumber(lx); double y = LS.cknumber(ly); double radius = LS.cknumber(lradius); bool omit_nowhere = LS.ckboolean(lomit_nowhere); util::IdVector idv = w->plane_map_.scan_radius(plane, x, y, radius, omit_nowhere, 0, false); tangible_getall(LS, list, idv); return LS.result(); } LuaDefine(world_wait, "f") { if ((lua_gettop(L) != 1) || (lua_type(L, -1) != LUA_TNUMBER)) { luaL_error(L, "Argument to wait must be a number."); } return lua_yield(L, 1); } LuaDefine(tangible_nopredict, "c") { if (lua_gettop(L) != 0) { luaL_error(L, "tangible.nopredict takes no arguments"); } World *w = World::fetch_global_pointer(L); if (util::world_type_authoritative(w->world_type_)) { return 0; } else { return lua_yield(L, 0); } } LuaDefine(world_getregistry, "f") { lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; } LuaDefine(world_xtype, "f") { LuaArg tab; LuaRet rtype; LuaStack LS(L, tab, rtype); int xt = LS.xtype(tab); LS.set(rtype, xt); return LS.result(); } LuaDefine(world_settabletype, "f") { LuaArg tab, ttype; LuaStack LS(L, tab, ttype); if (!LS.istable(tab)) { luaL_error(L, "Not a table"); } int tt = LS.ckinteger(ttype); if ((tt < LUA_TT_GENERAL) || (tt > LUA_TT_CLASS)) { luaL_error(L, "table type out of range"); } LS.settabletype(tab, tt); return LS.result(); } LuaDefine(world_pprint, "f") { World *w = World::fetch_global_pointer(L); std::ostream *ostream = w->lthread_print_stream(); LuaStack LS(L); for (int i = 1; i <= lua_gettop(L); i++) { LuaSpecial root(i); pprint(LS, root, true, ostream); (*ostream) << std::endl; } return LS.result(); } LuaDefine(world_print, "f") { World *w = World::fetch_global_pointer(L); std::ostream *ostream = w->lthread_print_stream(); LuaStack LS(L); for (int i = 1; i <= lua_gettop(L); i++) { LuaSpecial root(i); atomic_print(LS, root, ostream); (*ostream) << std::endl; } return LS.result(); }