From cacfae9502441cd3014928364d97b9864d95c8fd Mon Sep 17 00:00:00 2001 From: HybridDog Date: Mon, 4 Jan 2016 10:55:39 +0100 Subject: [PATCH] add comments and begin making obsidian portal always work --- nether/pearl.lua | 18 +- nether/portal.lua | 652 ++++++++++++++++++++++++---------------------- 2 files changed, 355 insertions(+), 315 deletions(-) diff --git a/nether/pearl.lua b/nether/pearl.lua index 7ecbffe..d02f2e8 100644 --- a/nether/pearl.lua +++ b/nether/pearl.lua @@ -56,16 +56,16 @@ end -- teleports the player there if there's free space local function teleport_player(pos, player) - local nd2 = is_soft(pos) - pos.y = pos.y+1 - local nd3 = is_soft(pos) - if nd2 - and nd3 then - pos.y = pos.y-1.4 - player:moveto(pos) - return true + if not is_soft(pos) then + return false end - return false + if not is_soft({x=pos.x, y=pos.y+1, z=pos.z}) + and not is_soft({x=pos.x, y=pos.y-1, z=pos.z}) then + return false + end + pos.y = pos.y+0.05 + player:moveto(pos) + return true end --[[ diff --git a/nether/portal.lua b/nether/portal.lua index 3d5a64a..94dc19d 100644 --- a/nether/portal.lua +++ b/nether/portal.lua @@ -20,12 +20,15 @@ table.icontains = table.icontains or function(t, v) end local players_in_nether = {} -local file = io.open(minetest.get_worldpath()..'/nether_players', "r") -if file then - local contents = file:read('*all') - io.close(file) - if contents then - players_in_nether = string.split(contents, " ") +-- only get info from file if nether prisons +if nether_prisons then + local file = io.open(minetest.get_worldpath()..'/nether_players', "r") + if file then + local contents = file:read('*all') + io.close(file) + if contents then + players_in_nether = string.split(contents, " ") + end end end @@ -57,7 +60,7 @@ local function player_to_nether(player, safe) if table.icontains(players_in_nether, pname) then return end - table.insert(players_in_nether, pname) + players_in_nether[#players_in_nether+1] = pname save_nether_players() if not safe then minetest.chat_send_player(pname, "For any reason you arrived here. Type /nether_help to find out things like craft recipes.") @@ -84,59 +87,61 @@ local function player_from_nether(player) end -if nether_prisons then - local function player_exists(name) - for _,player in pairs(minetest.get_connected_players()) do - if player:get_player_name() == name then - return true - end +local function player_exists(name) + for _,player in pairs(minetest.get_connected_players()) do + if player:get_player_name() == name then + return true end - return false end + return false +end - -- Chatcommands (edited) written by sss - minetest.register_chatcommand("to_hell", { - params = "[]", - description = "Send someone to hell", - func = function(name, pname) - if not minetest.check_player_privs(name, {nether=true}) then - return false, "You need the nether priv to execute this chatcommand." - end - if not player_exists(pname) then - pname = name - end - local player = minetest.get_player_by_name(pname) - if not player then - return false, "Something went wrong." - end - minetest.chat_send_player(pname, "Go to hell !!!") - player_to_nether(player) - return true, pname.." is now in the nether." +-- Chatcommands (edited) written by sss +minetest.register_chatcommand("to_hell", { + params = "[]", + description = "Send someone to hell", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, "You need the nether priv to execute this chatcommand." end - }) - - minetest.register_chatcommand("from_hell", { - params = "[]", - description = "Extract from hell", - func = function(name, pname) - if not minetest.check_player_privs(name, {nether=true}) then - return false, "You need the nether priv to execute this chatcommand." - end - if not player_exists(pname) then - pname = name - end - local player = minetest.get_player_by_name(pname) - if not player then - return false, "Something went wrong." - end - minetest.chat_send_player(pname, "You are free now") - player_from_nether(player) - local pos = player:getpos() - player:moveto({x=pos.x, y=100, z=pos.z}) - return true, pname.." is now out of the nether." + if not player_exists(pname) then + pname = name end - }) + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + minetest.chat_send_player(pname, "Go to hell !!!") + player_to_nether(player) + return true, pname.." is now in the nether." + end +}) +minetest.register_chatcommand("from_hell", { + params = "[]", + description = "Extract from hell", + func = function(name, pname) + if not minetest.check_player_privs(name, {nether=true}) then + return false, "You need the nether priv to execute this chatcommand." + end + if not player_exists(pname) then + pname = name + end + local player = minetest.get_player_by_name(pname) + if not player then + return false, "Something went wrong." + end + minetest.chat_send_player(pname, "You are free now") + player_from_nether(player) + local pos = player:getpos() + player:moveto({x=pos.x, y=100, z=pos.z}) + return true, pname.." is now out of the nether." + end +}) + + +if nether_prisons then + -- randomly set player position when he/she dies in nether minetest.register_on_respawnplayer(function(player) local pname = player:get_player_name() if not table.icontains(players_in_nether, pname) then @@ -154,8 +159,9 @@ if nether_prisons then return true end) + -- function for teleporting players where they belong to local function update_players() - for _,player in ipairs(minetest.get_connected_players()) do + for _,player in pairs(minetest.get_connected_players()) do local pname = player:get_player_name() local ppos = player:getpos() if table.icontains(players_in_nether, pname) then @@ -176,6 +182,7 @@ if nether_prisons then end end + -- fix wrong player positions local timer = 0 --doesn't work if the server lags minetest.register_globalstep(function(dtime) timer = timer + dtime; @@ -186,6 +193,7 @@ if nether_prisons then end end) + -- set background when player joins minetest.register_on_joinplayer(function(player) minetest.after(0, function(player) if player:getpos().y < nether.start then @@ -193,266 +201,297 @@ if nether_prisons then end end, player) end) - - local function remove_portal_essence(pos) - for z = -1,1 do - for y = -2,2 do - for x = -1,1 do - local p = {x=pos.x+x, y=pos.y+y, z=pos.z+z} - if minetest.get_node(p).name == "nether:portal" then - minetest.remove_node(p) - end +else + -- test if player is in nether when he/she joins + minetest.register_on_joinplayer(function(player) + minetest.after(0, function(player) + if player:getpos().y < nether.start then + if table.icontains(players_in_nether, pname) then + return end - end - end - end - - minetest.register_abm({ - nodenames = {"nether:portal"}, - interval = 1, - chance = 2, - catch_up = false, - action = function(pos, node) - if not abm_allowed then + players_in_nether[#players_in_nether+1] = pname return end - minetest.add_particlespawner({ - amount = 32, - time = 4, - minpos = {x=pos.x-0.25, y=pos.y-0.5, z=pos.z-0.25}, - maxpos = {x=pos.x+0.25, y=pos.y+0.34, z=pos.z+0.25}, - minvel = {x=0, y=1, z=0}, - maxvel = {x=0, y=2, z=0}, - minacc = {x=-0.5,y=-3,z=-0.3}, - maxacc = {x=0.5,y=-0.4,z=0.3}, - minexptime = 1, - maxexptime = 1, - minsize = 0.4, - maxsize = 3, - collisiondetection = true, - texture = "nether_portal_particle.png^[transform"..math.random(0,7), - }) - for _,obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do - if obj:is_player() then - local meta = minetest.get_meta(pos) - local target = minetest.string_to_pos(meta:get_string("target")) - if target then - minetest.after(3, function(obj, pos, target) - local pname = obj:get_player_name() - if table.icontains(players_in_nether, pname) then - return - end - local objpos = obj:getpos() - objpos.y = objpos.y+0.1 -- Fix some glitches at -8000 - if minetest.get_node(vector.round(objpos)).name ~= "nether:portal" then - return - end - - remove_portal_essence(pos) - - minetest.sound_play("nether_portal_usual", {to_player=pname, gain=1}) - player_to_nether(obj) - --obj:setpos(target) - - end, obj, pos, target) - end + for i,name in pairs(players_in_nether) do + if name == pname then + players_in_nether[i] = nil + return end end - end, - }) - - local function move_check(p1, max, dir) - local p = {x=p1.x, y=p1.y, z=p1.z} - local d = math.abs(max-p1[dir]) / (max-p1[dir]) - while p[dir] ~= max do - p[dir] = p[dir] + d - if minetest.get_node(p).name ~= "default:obsidian" then - return false - end - end - return true - end - - local function check_portal(p1, p2) - if p1.x ~= p2.x then - if not move_check(p1, p2.x, "x") then - return false - end - if not move_check(p2, p1.x, "x") then - return false - end - elseif p1.z ~= p2.z then - if not move_check(p1, p2.z, "z") then - return false - end - if not move_check(p2, p1.z, "z") then - return false - end - else - return false - end - - if not move_check(p1, p2.y, "y") then - return false - end - if not move_check(p2, p1.y, "y") then - return false - end - - return true - end - - local function is_portal(pos) - for d=-3,3 do - for y=-4,4 do - local px = {x=pos.x+d, y=pos.y+y, z=pos.z} - local pz = {x=pos.x, y=pos.y+y, z=pos.z+d} - if check_portal(px, {x=px.x+3, y=px.y+4, z=px.z}) then - return px, {x=px.x+3, y=px.y+4, z=px.z} - end - if check_portal(pz, {x=pz.x, y=pz.y+4, z=pz.z+3}) then - return pz, {x=pz.x, y=pz.y+4, z=pz.z+3} - end - end - end - end - - local function make_portal(pos) - local p1, p2 = is_portal(pos) - if not p1 - or not p2 then - print("[nether] something failed.") - return false - end - - if p1.y < nether.start then - print("[nether] aborted, obsidian portals can't be used to get out") - return - end - - for d=1,2 do - for y=p1.y+1,p2.y-1 do - local p - if p1.z == p2.z then - p = {x=p1.x+d, y=y, z=p1.z} - else - p = {x=p1.x, y=y, z=p1.z+d} - end - if minetest.get_node(p).name ~= "air" then - return false - end - end - end - - local param2 - if p1.z == p2.z then - param2 = 0 - else - param2 = 1 - end - - local target = {x=p1.x, y=p1.y, z=p1.z} - target.x = target.x + 1 - target.y = portal_target + math.random(4) - - for d=0,3 do - for y=p1.y,p2.y do - local p = {} - if param2 == 0 then - p = {x=p1.x+d, y=y, z=p1.z} - else - p = {x=p1.x, y=y, z=p1.z+d} - end - if minetest.get_node(p).name == "air" then - minetest.set_node(p, {name="nether:portal", param2=param2}) - end - local meta = minetest.get_meta(p) - meta:set_string("p1", minetest.pos_to_string(p1)) - meta:set_string("p2", minetest.pos_to_string(p2)) - meta:set_string("target", minetest.pos_to_string(target)) - end - end - print("[nether] construction accepted.") - return true - end - - minetest.override_item("default:obsidian", { - on_destruct = function(pos) - local meta = minetest.get_meta(pos) - local p1 = minetest.string_to_pos(meta:get_string("p1")) - local p2 = minetest.string_to_pos(meta:get_string("p2")) - local target = minetest.string_to_pos(meta:get_string("target")) - if not p1 or not p2 then - return - end - for x=p1.x,p2.x do - for y=p1.y,p2.y do - for z=p1.z,p2.z do - local nn = minetest.get_node({x=x,y=y,z=z}).name - if nn == "default:obsidian" or nn == "nether:portal" then - if nn == "nether:portal" then - minetest.remove_node({x=x,y=y,z=z}) - end - local m = minetest.get_meta({x=x,y=y,z=z}) - m:set_string("p1", "") - m:set_string("p2", "") - m:set_string("target", "") - end - end - end - end - meta = minetest.get_meta(target) - if not meta then - return - end - p1 = minetest.string_to_pos(meta:get_string("p1")) - p2 = minetest.string_to_pos(meta:get_string("p2")) - if not p1 or not p2 then - return - end - for x=p1.x,p2.x do - for y=p1.y,p2.y do - for z=p1.z,p2.z do - local nn = minetest.get_node({x=x,y=y,z=z}).name - if nn == "default:obsidian" or nn == "nether:portal" then - if nn == "nether:portal" then - minetest.remove_node({x=x,y=y,z=z}) - end - local m = minetest.get_meta({x=x,y=y,z=z}) - m:set_string("p1", "") - m:set_string("p2", "") - m:set_string("target", "") - end - end - end - end - end - }) - - minetest.after(0.1, function() - minetest.override_item("default:mese_crystal_fragment", { - on_place = function(stack, player, pt) - if pt.under - and minetest.get_node(pt.under).name == "default:obsidian" then - print("[nether] tries to enable a portal") - local done = make_portal(pt.under) - if done then - minetest.chat_send_player( - player:get_player_name(), - "Warning: If you are in the nether you may not be able to find the way out!" - ) - if not minetest.setting_getbool("creative_mode") then - stack:take_item() - end - end - end - return stack - end - }) + end, player) end) end +-- removes the violet stuff from the obsidian portal +local function remove_portal_essence(pos) + for z = -1,1 do + for y = -2,2 do + for x = -1,1 do + local p = {x=pos.x+x, y=pos.y+y, z=pos.z+z} + if minetest.get_node(p).name == "nether:portal" then + minetest.remove_node(p) + end + end + end + end +end +-- change parts of the particledefinition instead of recreating it every time +local particledef = { + amount = 32, + time = 4, + minvel = {x=0, y=1, z=0}, + maxvel = {x=0, y=2, z=0}, + minacc = {x=-0.5,y=-3,z=-0.3}, + maxacc = {x=0.5,y=-0.4,z=0.3}, + minexptime = 1, + maxexptime = 1, + minsize = 0.4, + maxsize = 3, + collisiondetection = true, +} + +-- teleports player to neter (obsidian portal) +local function obsi_teleport_player(obj, pos, target) + local pname = obj:get_player_name() + if table.icontains(players_in_nether, pname) then + return + end + local objpos = obj:getpos() + objpos.y = objpos.y+0.1 -- Fix some glitches at -8000 + if minetest.get_node(vector.round(objpos)).name ~= "nether:portal" then + return + end + + remove_portal_essence(pos) + + minetest.sound_play("nether_portal_usual", {to_player=pname, gain=1}) + player_to_nether(obj) + --obj:setpos(target) +end + +-- abm for particles of the obsidian portal essence and for teleporting +minetest.register_abm({ + nodenames = {"nether:portal"}, + interval = 1, + chance = 2, + catch_up = false, + action = function(pos, node) + if not abm_allowed then + return + end + particledef.minpos = {x=pos.x-0.25, y=pos.y-0.5, z=pos.z-0.25} + particledef.maxpos = {x=pos.x+0.25, y=pos.y+0.34, z=pos.z+0.25} + particledef.texture = "nether_portal_particle.png^[transform"..math.random(0,7) + minetest.add_particlespawner(particledef) + for _,obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do + if obj:is_player() then + local meta = minetest.get_meta(pos) + local target = minetest.string_to_pos(meta:get_string("target")) + if target then + minetest.after(3, obsi_teleport_player, obj, pos, target) + end + end + end + end, +}) + +local function move_check(p1, max, dir) + local p = {x=p1.x, y=p1.y, z=p1.z} + local d = math.abs(max-p1[dir]) / (max-p1[dir]) + while p[dir] ~= max do + p[dir] = p[dir] + d + if minetest.get_node(p).name ~= "default:obsidian" then + return false + end + end + return true +end + +local function check_portal(p1, p2) + if p1.x ~= p2.x then + if not move_check(p1, p2.x, "x") then + return false + end + if not move_check(p2, p1.x, "x") then + return false + end + elseif p1.z ~= p2.z then + if not move_check(p1, p2.z, "z") then + return false + end + if not move_check(p2, p1.z, "z") then + return false + end + else + return false + end + + if not move_check(p1, p2.y, "y") then + return false + end + if not move_check(p2, p1.y, "y") then + return false + end + + return true +end + +-- tests if it's an obsidian portal +local function is_portal(pos) + for d=-3,3 do + for y=-4,4 do + local px = {x=pos.x+d, y=pos.y+y, z=pos.z} + local pz = {x=pos.x, y=pos.y+y, z=pos.z+d} + if check_portal(px, {x=px.x+3, y=px.y+4, z=px.z}) then + return px, {x=px.x+3, y=px.y+4, z=px.z} + end + if check_portal(pz, {x=pz.x, y=pz.y+4, z=pz.z+3}) then + return pz, {x=pz.x, y=pz.y+4, z=pz.z+3} + end + end + end +end + +-- adds the violed portal essence +local function make_portal(pos) + local p1, p2 = is_portal(pos) + if not p1 + or not p2 then + print("[nether] something failed.") + return false + end + + if p1.y < nether.start then + print("[nether] aborted, obsidian portals can't be used to get out") + return + end + + for d=1,2 do + for y=p1.y+1,p2.y-1 do + local p + if p1.z == p2.z then + p = {x=p1.x+d, y=y, z=p1.z} + else + p = {x=p1.x, y=y, z=p1.z+d} + end + if minetest.get_node(p).name ~= "air" then + return false + end + end + end + + local param2 + if p1.z == p2.z then + param2 = 0 + else + param2 = 1 + end + + local target = {x=p1.x, y=p1.y, z=p1.z} + target.x = target.x + 1 + target.y = portal_target + math.random(4) + + for d=0,3 do + for y=p1.y,p2.y do + local p = {} + if param2 == 0 then + p = {x=p1.x+d, y=y, z=p1.z} + else + p = {x=p1.x, y=y, z=p1.z+d} + end + if minetest.get_node(p).name == "air" then + minetest.set_node(p, {name="nether:portal", param2=param2}) + end + local meta = minetest.get_meta(p) + meta:set_string("p1", minetest.pos_to_string(p1)) + meta:set_string("p2", minetest.pos_to_string(p2)) + meta:set_string("target", minetest.pos_to_string(target)) + end + end + print("[nether] construction accepted.") + return true +end + +-- destroy the portal when destroying obsidian +minetest.override_item("default:obsidian", { + on_destruct = function(pos) + local meta = minetest.get_meta(pos) + local p1 = minetest.string_to_pos(meta:get_string("p1")) + local p2 = minetest.string_to_pos(meta:get_string("p2")) + local target = minetest.string_to_pos(meta:get_string("target")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.remove_node({x=x,y=y,z=z}) + end + local m = minetest.get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + meta = minetest.get_meta(target) + if not meta then + return + end + p1 = minetest.string_to_pos(meta:get_string("p1")) + p2 = minetest.string_to_pos(meta:get_string("p2")) + if not p1 or not p2 then + return + end + for x=p1.x,p2.x do + for y=p1.y,p2.y do + for z=p1.z,p2.z do + local nn = minetest.get_node({x=x,y=y,z=z}).name + if nn == "default:obsidian" or nn == "nether:portal" then + if nn == "nether:portal" then + minetest.remove_node({x=x,y=y,z=z}) + end + local m = minetest.get_meta({x=x,y=y,z=z}) + m:set_string("p1", "") + m:set_string("p2", "") + m:set_string("target", "") + end + end + end + end + end +}) + +-- override mese crystal fragment for making an obsidian portal +minetest.after(0.1, function() + minetest.override_item("default:mese_crystal_fragment", { + on_place = function(stack, player, pt) + if pt.under + and minetest.get_node(pt.under).name == "default:obsidian" then + --print("[nether] tries to enable a portal") + local done = make_portal(pt.under) + if done then + minetest.chat_send_player( + player:get_player_name(), + "Warning: If you are in the nether you may not be able to find the way out!" + ) + if not minetest.setting_getbool("creative_mode") then + stack:take_item() + end + end + end + return stack + end + }) +end) + + +-- a not filled square vector.square = vector.square or function(r) local tab, n = {}, 1 @@ -467,6 +506,7 @@ function(r) return tab end +-- detects if it's a portal local function netherport(pos) local x, y, z = pos.x, pos.y, pos.z for _,i in ipairs({-1, 3}) do