diff --git a/mods/worldedge/README.md b/mods/worldedge/README.md new file mode 100644 index 00000000..abdaef14 --- /dev/null +++ b/mods/worldedge/README.md @@ -0,0 +1,13 @@ +worldedge +========= + +A Minetest Mod that teleports you to the other side of the map when you reach its edge. +This gives the illusion that that world is round and you can walk all the way around. + +You can change the worlds edge by changing the first variable in init.lua + local edge = 30000 + +License of code: WTFPL + +Written by Amaz +Modified by Don \ No newline at end of file diff --git a/mods/worldedge/depends.txt b/mods/worldedge/depends.txt new file mode 100644 index 00000000..e69de29b diff --git a/mods/worldedge/init.lua b/mods/worldedge/init.lua new file mode 100644 index 00000000..5e672dd7 --- /dev/null +++ b/mods/worldedge/init.lua @@ -0,0 +1,145 @@ +-------------- +-- TODO: Check for terrain height + +-- Defines the edge of a world +local edge = 30000 +-- Radius which should be checked for a good teleportation place +local radius = 2 +-------------- + +local count = 0 +local waiting_list = {} +--[[ Explanation of waiting_list table + Index = Player name + Value = { + player = Player to teleport + pos = Destination + obj = Attacked entity + notified = When the player must wait longer... + } +]] + +minetest.register_globalstep(function(dtime) + count = count + dtime + if count < 3 then + return + end + count = 0 + + for k, v in pairs(waiting_list) do + if v.player and v.player:is_player() then + local pos = get_surface_pos(v.pos) + if pos then + v.obj:setpos(pos) + minetest.after(0.2, function(p, o) + p:set_detach() + o:remove() + end, v.player, v.obj) + waiting_list[k] = nil + elseif not v.notified then + v.notified = true + minetest.chat_send_player(k, "Sorry, we have not found a free place yet. Please be patient.") + end + else + v.obj:remove() + waiting_list[k] = nil + end + end + + local newedge = edge - 5 + -- Check if the players are near the edge and teleport them + local players = minetest.get_connected_players() + for i, player in ipairs(players) do + local name = player:get_player_name() + if not waiting_list[name] then + local pos = vector.round(player:getpos()) + local newpos = nil + if pos.x >= edge then + newpos = {x = -newedge, y = 10, z = pos.z} + elseif pos.x <= -edge then + newpos = {x = newedge, y = 10, z = pos.z} + end + + if pos.z >= edge then + newpos = {x = pos.x, y = 10, z = -newedge} + newpos.y = get_surface_pos(newpos).y + elseif pos.z <= -edge then + newpos = {x = pos.x, y = 10, z = newedge} + newpos.y = get_surface_pos(newpos).y + end + + -- Teleport the player + if newpos then + minetest.chat_send_player(name, "Please wait a few seconds. We will teleport you soon.") + local obj = minetest.add_entity(newpos, "worldedge:lock") + player:set_attach(obj, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}) + waiting_list[name] = { + player = player, + pos = newpos, + obj = obj + } + obj:setpos(newpos) + end + end + end +end) + +function get_surface_pos(pos) + local minp = { + x = pos.x - radius - 1, + y = -10, + z = pos.z - radius - 1 + } + local maxp = { + x = pos.x + radius - 1, + y = 50, + z = pos.z + radius - 1 + } + + local c_air = minetest.get_content_id("air") + local c_ignore = minetest.get_content_id("ignore") + + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map(minp, maxp) + local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} + local data = vm:get_data() + + local seen_air = false + local deepest_place = vector.new(pos) + deepest_place.y = 50 + + for x = minp.x, maxp.x do + for z = minp.z, maxp.z do + local solid = 0 + for y = deepest_place.y, -10, -1 do + local node = data[area:index(x, y, z)] + if y < deepest_place.y and node == c_air then + deepest_place = vector.new(x, y, z) + seen_air = true + end + if solid > 5 then + -- Do not find caves! + break + end + if node ~= c_air and node ~= c_ignore then + solid = solid + 1 + end + end + end + end + + if seen_air then + return deepest_place + else + return false + end +end + +minetest.register_entity("worldedge:lock", { + initial_properties = { + is_visible = false + }, + on_activate = function(staticdata, dtime_s) + --self.object:set_armor_groups({immortal = 1}) + end +})