forked from mtcontrib/nether-pack
		
	add comments and begin making obsidian portal always work
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
--[[
 | 
			
		||||
 
 | 
			
		||||
@@ -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 = "[<player_name>]",
 | 
			
		||||
		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 = "[<player_name>]",
 | 
			
		||||
	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 = "[<player_name>]",
 | 
			
		||||
		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 = "[<player_name>]",
 | 
			
		||||
	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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user