local ns = { beacons = {}, teleports = {} } minetest.register_entity(":teleport_box", { initial_properties = { visual = "mesh", mesh = "teleport_box.gltf", textures = {"teleport_box.png"}, visual_size = vector.new(1,1,1) *5, static_save = false, use_texture_alpha = true, backface_culling = false, pointable = false, glow = 14 }, on_activate = function(e) e.object:set_armor_groups{immortal = 1} end, on_step = function(e, dtime) end }) minetest.register_entity(":teleport_beacon", { initial_properties = { visual = "mesh", mesh = "teleport_beacon.gltf", textures = {"teleport_beacon.png"}, use_texture_alpha = true, backface_culling = false, pointable = false, glow = 14 }, on_activate = function(e, name) if name then e.owner = name end if not ns.beacons[e.owner] or ns.beacons[e.owner].marker then e.object:remove() return end ns.beacons[e.owner].marker = e.object e.object:set_armor_groups{immortal = 1} e.object:set_animation({x=1,y=1}, 1.5, 0, false) end, get_staticdata = function(e) return e.owner end }) -- HACK: Override the builtin item to be teleportable, so that -- entity teleportation can remain opt-in. local def = table.copy(minetest.registered_entities["__builtin:item"]) def._teleportable = true minetest.register_entity(":__builtin:item", def) function ns.do_teleport(from, to, radius) for obj in minetest.objects_in_area(from:offset(-radius, -radius, -radius), from:offset(radius, radius, radius)) do if obj:is_player() or obj:get_luaentity()._teleportable then obj:set_pos(obj:get_pos() -from +to) end end end function ns.begin_teleport(from, to, radius) ns.teleports[to:to_string()] = true radius = radius or 2.5 local box1 = minetest.add_entity(from, "teleport_box") local box2 = minetest.add_entity(to, "teleport_box") box1:set_animation({x=0,y=1.25}, 1, 0, false) box2:set_animation({x=0,y=1.25}, 1, 0, false) minetest.after(1, function() box1:set_animation({x=1.25,y=2.25}, 1, 0, true) box2:set_animation({x=1.25,y=2.25}, 1, 0, true) end) minetest.after(10, function() box1:set_animation({x=2.25,y=2.5}, 1, 0, false) box2:set_animation({x=2.25,y=2.5}, 1, 0, false) minetest.after(0.25, function() box1:set_animation({x=2.5,y=2.5}, 1, 0, false) box2:set_animation({x=2.5,y=2.5}, 1, 0, false) box1:set_properties{use_texture_alpha = false} box2:set_properties{use_texture_alpha = false} end) minetest.after(1, function() ns.do_teleport(from, to, radius) minetest.after(0.5, function() box1:set_animation({x=2.5,y=3}, 1, 0, false) box2:set_animation({x=2.5,y=3}, 1, 0, false) minetest.after(0.5, function() box1:remove() box2:remove() ns.teleports[to:to_string()] = nil end) end) end) end) end function ns.place_beacon(name, pos) if ns.beacons[name] and ns.beacons[name].marker then ns.beacons[name].marker:remove() end ns.beacons[name] = { pos = pos } local obj = minetest.add_entity(pos, "teleport_beacon", name) obj:set_animation({x=0,y=1}, 1.5, 0, false) end minetest.register_craftitem(":teleport", { inventory_image = "rgt_acacia_planks.png", on_place = function(s, p, pt) ns.place_beacon(p:get_player_name(), pt.above) end, on_use = function(s, p, pt) local name = p:get_player_name() if not pt.above then return end if ns.beacons[name] then if ns.teleports[ns.beacons[name].pos:to_string()] then tell(name, "This destination is currently is use by another spell.") else ns.begin_teleport(pt.above, ns.beacons[name].pos) end else tell(name, "No beacon placed.") end end })