2015-02-18 18:34:03 +01:00
--code copied from Pilzadam's nether mod and edited
2015-12-31 15:15:39 +01:00
-- kills the player if he uses PilzAdam portal
2015-02-18 18:34:03 +01:00
local portal_target = nether.buildings + 1
2022-08-16 17:12:37 +02:00
local damage_enabled = minetest.settings : get_bool " enable_damage "
2016-01-04 11:48:21 +01:00
local mclike_portal = false
2015-02-18 18:34:03 +01:00
local abm_allowed
minetest.after ( 5 , function ( )
abm_allowed = true
end )
2018-08-15 17:31:15 +02:00
local save_path = minetest.get_worldpath ( ) .. " /nether_players "
2015-02-18 18:34:03 +01:00
local players_in_nether = { }
2022-08-15 15:46:47 +02:00
-- Load the list of players which are trapped in the nether
2022-08-16 17:12:37 +02:00
-- (or would be trapped if nether.trap_players was true)
2022-08-15 15:46:47 +02:00
do
2018-08-15 17:31:15 +02:00
local file = io.open ( save_path , " r " )
2022-08-15 15:46:47 +02:00
if file then
local contents = file : read " *all "
io.close ( file )
if contents then
local playernames = string.split ( contents , " " )
for i = 1 , # playernames do
players_in_nether [ playernames [ i ] ] = true
end
end
2015-02-18 18:34:03 +01:00
end
end
2024-02-20 21:03:32 +01:00
-- Nether aware mods will need to know if a player is in the nether.
2024-02-20 23:53:14 +01:00
nether [ ' is_player_in_nether ' ] = function ( player )
2024-02-20 21:03:32 +01:00
local pname = player : get_player_name ( )
if players_in_nether [ pname ] == nil then
return false
else
return true
end
end
2024-02-20 23:53:14 +01:00
-- Nether aware mods may have other means of moving players between the Nether and Overworld, and if so, they should tell us about it so we can keep track of the player state.
nether [ ' external_nether_teleport ' ] = function ( player )
local pos = player : get_pos ( )
local pname = player : get_player_name ( )
if ( pos.y < nether.start ) and ( pos.y >= nether.bottom ) then
players_in_nether [ pname ] = true
else
players_in_nether [ pname ] = nil
end
end
2024-02-20 21:03:32 +01:00
2015-02-18 18:34:03 +01:00
local function save_nether_players ( )
2018-08-15 17:31:15 +02:00
local playernames , n = { } , 1
for name in pairs ( players_in_nether ) do
playernames [ n ] = name
n = n + 1
2015-02-18 18:34:03 +01:00
end
2018-08-15 17:31:15 +02:00
local f = io.open ( save_path , " w " )
assert ( f , " Could not open nether_players file for writing. " )
f : write ( table.concat ( playernames , " " ) )
2015-02-18 18:34:03 +01:00
io.close ( f )
end
local update_background
2022-08-16 17:12:37 +02:00
if nether.trap_players then
2015-02-18 18:34:03 +01:00
function update_background ( player , down )
if down then
player : set_sky ( { r = 15 , g = 0 , b = 0 } , " plain " )
else
player : set_sky ( nil , " regular " )
end
end
else
function update_background ( ) end
end
2016-01-04 11:48:21 +01:00
-- returns nodename if area is generated, else calls generation function
local function generated_or_generate ( pos )
2018-08-15 16:52:04 +02:00
local node = minetest.get_node_or_nil ( pos )
if node then
return node.name
2016-01-04 11:48:21 +01:00
end
minetest.get_voxel_manip ( ) : read_from_map ( pos , pos )
2018-08-15 16:52:04 +02:00
node = minetest.get_node_or_nil ( pos )
if not node then
2016-01-04 11:48:21 +01:00
minetest.emerge_area ( vector.subtract ( pos , 80 ) , vector.add ( pos , 80 ) )
return false
end
2018-08-15 16:52:04 +02:00
return node.name
2016-01-04 11:48:21 +01:00
end
-- where the player appears after dying
local function get_player_died_target ( player )
2021-12-22 18:24:47 +01:00
local target = vector.add ( player : get_pos ( ) ,
2018-08-15 16:57:23 +02:00
{ x = math.random ( - 100 , 100 ) , y = 0 , z = math.random ( - 100 , 100 ) } )
2016-01-04 11:48:21 +01:00
target.y = portal_target + math.random ( 4 )
return target
end
-- used for obsidian portal
2018-08-15 19:52:39 +02:00
local function obsidian_teleport ( player , pname , target )
2024-02-20 22:24:29 +01:00
if nether.trap_players then
minetest.chat_send_player ( pname , " For any reason you arrived here. Type " ..
" /nether_help to find out things like craft recipes. " )
players_in_nether [ pname ] = true
save_nether_players ( )
update_background ( player , true )
end
2018-08-15 19:52:39 +02:00
if target then
player : set_pos ( target )
else
2016-01-04 11:48:21 +01:00
player : set_hp ( 0 )
end
end
-- teleports players to nether or helps it
2018-08-15 19:52:39 +02:00
local function player_to_nether ( player , pos )
2015-02-18 18:34:03 +01:00
local pname = player : get_player_name ( )
2018-08-15 17:31:15 +02:00
players_in_nether [ pname ] = true
2015-02-18 18:34:03 +01:00
save_nether_players ( )
update_background ( player , true )
2018-08-15 19:52:39 +02:00
if pos then
player : set_pos ( pos )
return
end
minetest.chat_send_player ( pname , " For any reason you arrived here. " ..
" Type /nether_help to find out things like craft recipes. " )
2022-08-16 17:12:37 +02:00
if nether.trap_players then
player : set_hp ( 0 )
end
if not damage_enabled or not nether.trap_players then
2018-08-15 19:52:39 +02:00
player : set_pos ( get_player_died_target ( player ) )
end
2015-02-18 18:34:03 +01:00
end
2018-08-15 19:52:39 +02:00
local function player_from_nether ( player , pos )
2015-02-18 18:34:03 +01:00
local pname = player : get_player_name ( )
2018-08-15 17:31:15 +02:00
if players_in_nether [ pname ] then
players_in_nether [ pname ] = nil
2015-02-18 18:34:03 +01:00
save_nether_players ( )
end
2022-08-16 17:12:37 +02:00
update_background ( player , false )
2018-08-15 19:52:39 +02:00
player : set_pos ( pos )
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
local function player_exists ( name )
2018-08-15 17:31:15 +02:00
local players = minetest.get_connected_players ( )
for i = 1 , # players do
if players [ i ] : get_player_name ( ) == name then
2016-01-04 10:55:39 +01:00
return true
2015-02-18 18:34:03 +01:00
end
end
2016-01-04 10:55:39 +01:00
return false
end
2015-02-18 18:34:03 +01:00
2016-01-04 10:55:39 +01:00
-- 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
2018-08-15 16:57:23 +02:00
return false ,
" You need the nether privilege to execute this chatcommand. "
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
if not player_exists ( pname ) then
pname = name
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
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
2018-08-15 16:57:23 +02:00
return false ,
" You need the nether priv to execute this chatcommand. "
2016-01-04 10:55:39 +01:00
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 " )
2021-12-22 18:24:47 +01:00
local pos = player : get_pos ( )
2018-08-15 19:52:39 +02:00
player_from_nether ( player , { x = pos.x , y = 100 , z = pos.z } )
2016-01-04 10:55:39 +01:00
return true , pname .. " is now out of the nether. "
end
} )
2024-02-20 22:24:29 +01:00
-- Useful for debugging Nether player state tracking. Written by Deathwing777
minetest.register_chatcommand ( " in_hell " , {
params = " [<player_name>] " ,
description = " Is the player in 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
status = pname .. " is in the "
2024-02-20 23:53:14 +01:00
if nether.is_player_in_nether ( player ) then
status = status .. " NETHER! "
else
status = status .. " OVERWORLD! "
end
return true , status
end
} )
minetest.register_chatcommand ( " update_hells_registry " , {
params = " [<player_name>] " ,
description = " Update player state if they got to or from the nether in another way. " ,
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
nether.external_nether_teleport ( player )
status = pname .. " is in the "
if nether.is_player_in_nether ( player ) then
2024-02-20 22:24:29 +01:00
status = status .. " NETHER! "
else
status = status .. " OVERWORLD! "
end
return true , status
end
} )
2015-02-18 18:34:03 +01:00
2022-08-15 15:46:47 +02:00
-- Disallow teleportation and change spawn positions if the nether traps players
2022-08-16 17:12:37 +02:00
if nether.trap_players then
2016-01-04 10:55:39 +01:00
-- randomly set player position when he/she dies in nether
2016-01-01 12:39:21 +01:00
minetest.register_on_respawnplayer ( function ( player )
2015-02-18 18:34:03 +01:00
local pname = player : get_player_name ( )
2018-08-15 17:31:15 +02:00
if not players_in_nether [ pname ] then
2016-01-01 12:39:21 +01:00
return
end
2016-01-04 11:48:21 +01:00
local target = get_player_died_target ( player )
2018-08-15 19:52:39 +02:00
player : set_pos ( target )
2016-01-01 12:39:21 +01:00
minetest.after ( 0 , function ( pname , target )
2016-01-04 11:48:21 +01:00
-- fixes respawn bug
2016-01-01 12:39:21 +01:00
local player = minetest.get_player_by_name ( pname )
if player then
2022-08-20 19:57:09 +02:00
player : move_to ( target )
2016-01-01 12:39:21 +01:00
end
end , pname , target )
return true
end )
2018-08-15 19:52:39 +02:00
-- override set_pos etc. to disallow player teleportion by e.g. travelnet
local function can_teleport ( player , pos )
2018-08-18 20:00:30 +02:00
if not player : is_player ( ) then
-- the same metatable is used for entities
return true
end
2018-08-15 19:52:39 +02:00
local pname = player : get_player_name ( )
local in_nether = players_in_nether [ pname ] == true
-- test if the target is valid
if pos.y < nether.start then
if in_nether then
return true
end
elseif not in_nether then
return true
end
-- test if the current position is valid
local current_pos = player : get_pos ( )
local now_in_nether = current_pos.y < nether.start
if now_in_nether ~= in_nether then
if in_nether then
minetest.log ( " action " , " Player \" " .. pname ..
" \" has to be in the nether, teleporting it! " )
update_background ( player , true )
current_pos.y = portal_target
player : set_pos ( current_pos )
else
minetest.log ( " action " , " Player \" " .. pname ..
" \" must not be in the nether, teleporting it! " )
2022-08-16 17:12:37 +02:00
update_background ( player , false )
2018-08-15 19:52:39 +02:00
current_pos.y = 20
player : set_pos ( current_pos )
2015-02-18 18:34:03 +01:00
end
2018-08-15 19:52:39 +02:00
return false
2015-02-18 18:34:03 +01:00
end
2018-08-15 19:52:39 +02:00
minetest.chat_send_player ( pname ,
" You can not simply teleport to or from the nether! " )
minetest.log ( " action " , " Player \" " .. pname ..
" \" attempted to teleport from or to the nether, ignoring. " )
return false
2015-09-05 15:52:24 +02:00
end
2018-08-15 19:52:39 +02:00
local methods = { " set_pos " , " move_to " , " setpos " , " moveto " }
local metatable_overridden
2016-01-01 12:39:21 +01:00
minetest.register_on_joinplayer ( function ( player )
2018-08-15 19:52:39 +02:00
-- set the background when the player joins
2021-12-22 18:24:47 +01:00
if player : get_pos ( ) . y < nether.start then
2018-08-15 19:52:39 +02:00
update_background ( player , true )
end
-- overide set_pos etc. if not yet done
if metatable_overridden then
return
end
metatable_overridden = true
local mt = getmetatable ( player )
for i = 1 , # methods do
local methodname = methods [ i ]
local origfunc = mt [ methodname ]
mt [ methodname ] = function ( ... )
if can_teleport ( ... ) then
origfunc ( ... )
end
2016-01-01 12:39:21 +01:00
end
2018-08-15 19:52:39 +02:00
end
2016-01-01 12:39:21 +01:00
end )
2016-01-04 10:55:39 +01:00
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
-- 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
2016-01-01 12:39:21 +01:00
end
2015-02-18 18:34:03 +01:00
end
end
2016-01-04 10:55:39 +01:00
end
2015-02-18 18:34:03 +01:00
2016-01-04 10:55:39 +01:00
-- 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)
2016-01-04 11:48:21 +01:00
local function obsi_teleport_player ( player , pos , target )
local pname = player : get_player_name ( )
2018-08-15 17:31:15 +02:00
if players_in_nether [ pname ] then
2016-01-04 10:55:39 +01:00
return
end
2016-01-04 11:48:21 +01:00
2021-12-22 18:24:47 +01:00
local objpos = player : get_pos ( )
2016-01-04 10:55:39 +01:00
objpos.y = objpos.y + 0.1 -- Fix some glitches at -8000
if minetest.get_node ( vector.round ( objpos ) ) . name ~= " nether:portal " then
return
end
2018-08-15 19:52:39 +02:00
local has_teleported
2022-08-16 17:12:37 +02:00
if damage_enabled then
2018-08-15 19:52:39 +02:00
obsidian_teleport ( player , pname )
has_teleported = true
elseif not mclike_portal then
local target = vector.round ( get_player_died_target ( player ) )
if generated_or_generate ( target ) then
obsidian_teleport ( player , pname , target )
has_teleported = true
end
end
if not has_teleported then
2016-01-04 11:48:21 +01:00
-- e.g. ungenerated area
return
end
2016-01-04 10:55:39 +01:00
remove_portal_essence ( pos )
minetest.sound_play ( " nether_portal_usual " , { to_player = pname , gain = 1 } )
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 }
2018-08-15 16:57:23 +02:00
particledef.texture = " nether_portal_particle.png^[transform " ..
math.random ( 0 , 7 )
2016-01-04 10:55:39 +01:00
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
2016-01-01 12:39:21 +01:00
end
2016-01-04 10:55:39 +01:00
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
2015-02-18 18:34:03 +01:00
return false
end
2016-01-04 10:55:39 +01:00
end
return true
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
local function check_portal ( p1 , p2 )
if p1.x ~= p2.x then
if not move_check ( p1 , p2.x , " x " ) then
2015-02-18 18:34:03 +01:00
return false
end
2016-01-04 10:55:39 +01:00
if not move_check ( p2 , p1.x , " x " ) then
2015-02-18 18:34:03 +01:00
return false
end
2016-01-04 10:55:39 +01:00
elseif p1.z ~= p2.z then
if not move_check ( p1 , p2.z , " z " ) then
return false
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
if not move_check ( p2 , p1.z , " z " ) then
2015-02-18 18:34:03 +01:00
return false
end
2016-01-04 10:55:39 +01:00
else
return false
end
2015-02-18 18:34:03 +01:00
2016-01-04 10:55:39 +01:00
if not move_check ( p1 , p2.y , " y " ) then
return false
end
if not move_check ( p2 , p1.y , " y " ) then
return false
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
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 }
2016-01-01 12:39:21 +01:00
end
2016-01-04 10:55:39 +01:00
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 }
2015-02-18 18:34:03 +01:00
end
end
2016-01-04 10:55:39 +01:00
end
end
2016-01-01 12:39:21 +01:00
2016-01-04 11:48:21 +01:00
-- put here the function for creating a second portal
local create_second_portal
if mclike_portal then
function create_second_portal ( target )
-- change target here
end
end
-- adds the violet portal essence
2016-01-04 10:55:39 +01:00
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
2016-01-04 11:48:21 +01:00
local in_nether = p1.y < nether.start
if in_nether
and not mclike_portal then
2016-01-04 10:55:39 +01:00
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
2016-01-01 12:39:21 +01:00
if p1.z == p2.z then
2016-01-04 10:55:39 +01:00
p = { x = p1.x + d , y = y , z = p1.z }
2016-01-01 12:39:21 +01:00
else
2016-01-04 10:55:39 +01:00
p = { x = p1.x , y = y , z = p1.z + d }
end
if minetest.get_node ( p ) . name ~= " air " then
return false
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
end
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
local param2
if p1.z == p2.z then
param2 = 0
else
param2 = 1
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
local target = { x = p1.x , y = p1.y , z = p1.z }
target.x = target.x + 1
2016-01-04 11:48:21 +01:00
if in_nether then
target.y = 0
create_second_portal ( target )
else
target.y = portal_target + math.random ( 4 )
end
if not generated_or_generate ( target )
and mclike_portal then
return false
end
2016-01-04 10:55:39 +01:00
for d = 0 , 3 do
for y = p1.y , p2.y do
2021-12-22 18:16:01 +01:00
local p
2016-01-04 10:55:39 +01:00
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 }
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
if minetest.get_node ( p ) . name == " air " then
minetest.set_node ( p , { name = " nether:portal " , param2 = param2 } )
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
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 ) )
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
end
print ( " [nether] construction accepted. " )
return true
end
2016-01-01 12:39:21 +01:00
2016-01-04 10:55:39 +01:00
-- 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 } )
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
local m = minetest.get_meta ( { x = x , y = y , z = z } )
m : set_string ( " p1 " , " " )
m : set_string ( " p2 " , " " )
m : set_string ( " target " , " " )
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
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 } )
2016-01-01 12:39:21 +01:00
end
2016-01-04 10:55:39 +01:00
local m = minetest.get_meta ( { x = x , y = y , z = z } )
m : set_string ( " p1 " , " " )
m : set_string ( " p2 " , " " )
m : set_string ( " target " , " " )
2016-01-01 12:39:21 +01:00
end
2015-02-18 18:34:03 +01:00
end
2016-01-04 10:55:39 +01:00
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
local done = make_portal ( pt.under )
if done then
2022-08-20 19:57:09 +02:00
local pname = player : get_player_name ( )
minetest.chat_send_player ( pname ,
2018-08-15 16:57:23 +02:00
" Warning: If you are in the nether you may not be " ..
" able to find the way out! " )
2022-08-20 19:57:09 +02:00
if not minetest.is_creative_enabled ( pname ) then
2016-01-04 10:55:39 +01:00
stack : take_item ( )
2016-01-01 12:39:21 +01:00
end
end
end
2016-01-04 10:55:39 +01:00
return stack
end
} )
end )
2015-02-18 18:34:03 +01:00
2023-10-30 17:39:55 +01:00
-- Get positions for an empty square around the origin
2021-12-22 18:16:01 +01:00
local function vector_square ( r )
2015-02-18 18:34:03 +01:00
local tab , n = { } , 1
for i = - r + 1 , r do
for j = - 1 , 1 , 2 do
local a , b = r * j , i * j
2023-10-30 17:39:55 +01:00
tab [ n ] = { a , - b }
2015-02-18 18:34:03 +01:00
tab [ n + 1 ] = { b , a }
n = n + 2
end
end
return tab
end
2018-08-15 19:52:39 +02:00
local function is_netherportal ( pos )
2015-02-18 18:34:03 +01:00
local x , y , z = pos.x , pos.y , pos.z
2016-01-04 12:00:35 +01:00
for _ , i in pairs ( { - 1 , 3 } ) do
2015-02-18 18:34:03 +01:00
if minetest.get_node ( { x = x , y = y + i , z = z } ) . name ~= " nether:white " then
return
end
end
2021-12-22 18:16:01 +01:00
for _ , sn in pairs ( vector_square ( 1 ) ) do
2015-02-18 18:34:03 +01:00
if minetest.get_node ( { x = x + sn [ 1 ] , y = y - 1 , z = z + sn [ 2 ] } ) . name ~= " nether:netherrack "
or minetest.get_node ( { x = x + sn [ 1 ] , y = y + 3 , z = z + sn [ 2 ] } ) . name ~= " nether:blood_cooked " then
return
end
end
2021-12-22 18:16:01 +01:00
for _ , sn in pairs ( vector_square ( 2 ) ) do
2015-02-18 18:34:03 +01:00
if minetest.get_node ( { x = x + sn [ 1 ] , y = y - 1 , z = z + sn [ 2 ] } ) . name ~= " nether:netherrack_black "
or minetest.get_node ( { x = x + sn [ 1 ] , y = y + 3 , z = z + sn [ 2 ] } ) . name ~= " nether:wood_empty " then
return
end
end
for i = - 1 , 1 , 2 do
for j = - 1 , 1 , 2 do
if minetest.get_node ( { x = x + i , y = y + 2 , z = z + j } ) . name ~= " nether:apple " then
return
end
end
end
for i = - 2 , 2 , 4 do
for j = 0 , 2 do
for k = - 2 , 2 , 4 do
if minetest.get_node ( { x = x + i , y = y + j , z = z + k } ) . name ~= " nether:netherrack_brick_blue " then
return
end
end
end
end
for i = - 1 , 1 do
for j = - 1 , 1 do
if minetest.get_node ( { x = x + i , y = y + 4 , z = z + j } ) . name ~= " nether:wood_empty " then
return
end
end
end
return true
end
2015-12-28 20:04:38 +01:00
-- cache known portals
local known_portals_d = { }
local known_portals_u = { }
local function get_portal ( t , z , x )
return t [ z ] and t [ z ] [ x ]
end
local function set_portal ( t , z , x , y )
t [ z ] = t [ z ] or { }
t [ z ] [ x ] = y
end
2022-07-23 20:35:24 +02:00
local function get_player_nodepos ( player )
local pos = player : get_pos ( )
pos.y = pos.y + player : get_properties ( ) . collisionbox [ 2 ] + 0.5
return vector.round ( pos )
end
2016-01-04 13:25:06 +01:00
-- used when a player eats that fruit in a portal
2021-12-22 18:16:01 +01:00
function nether . teleport_player ( player )
if not player then
minetest.log ( " error " , " [nether] Missing player. " )
2015-02-18 18:34:03 +01:00
return
end
2022-07-23 20:35:24 +02:00
local pos = get_player_nodepos ( player )
2018-08-15 19:52:39 +02:00
if not is_netherportal ( pos ) then
2015-02-18 18:34:03 +01:00
return
end
minetest.sound_play ( " nether_teleporter " , { pos = pos } )
2016-01-04 12:00:35 +01:00
local meta = minetest.get_meta ( { x = pos.x , y = pos.y - 1 , z = pos.z } )
2015-02-18 18:34:03 +01:00
if pos.y < nether.start then
2015-12-28 20:04:38 +01:00
set_portal ( known_portals_d , pos.z , pos.x , pos.y )
2016-01-04 12:00:35 +01:00
local my = tonumber ( meta : get_string ( " y " ) )
local y = get_portal ( known_portals_u , pos.z , pos.x )
if y then
if y ~= my then
meta : set_string ( " y " , y )
end
else
y = my or 100
end
2018-08-15 19:52:39 +02:00
pos.y = y - 0.3
2016-01-04 12:00:35 +01:00
2018-08-15 19:52:39 +02:00
player_from_nether ( player , pos )
2015-02-18 18:34:03 +01:00
else
2015-12-28 20:04:38 +01:00
set_portal ( known_portals_u , pos.z , pos.x , pos.y )
2016-01-04 12:00:35 +01:00
local my = tonumber ( meta : get_string ( " y " ) )
local y = get_portal ( known_portals_d , pos.z , pos.x )
if y then
if y ~= my then
meta : set_string ( " y " , y )
end
else
y = my or portal_target + math.random ( 4 )
end
2018-08-15 19:52:39 +02:00
pos.y = y - 0.3
2016-01-04 12:00:35 +01:00
2018-08-15 19:52:39 +02:00
player_to_nether ( player , pos )
2015-02-18 18:34:03 +01:00
end
2015-12-28 18:38:09 +01:00
minetest.sound_play ( " nether_teleporter " , { pos = pos } )
2015-02-18 18:34:03 +01:00
return true
end