2017-08-17 01:16:29 +03:00
-- Parameters
local TCAVE = 0.6
local nobj_cave = nil
2017-08-18 03:42:26 +03:00
local SPAWN_MIN = mcl_vars.mg_end_min + 70
local SPAWN_MAX = mcl_vars.mg_end_min + 98
2017-08-21 19:30:37 +03:00
local mg_name = minetest.get_mapgen_setting ( " mg_name " )
2017-08-17 01:16:29 +03:00
-- 3D noise
local np_cave = {
offset = 0 ,
scale = 1 ,
spread = { x = 384 , y = 128 , z = 384 } , -- squashed 3:1
seed = 59033 ,
octaves = 5 ,
persist = 0.7
}
2017-08-17 19:14:49 +03:00
2017-08-17 04:27:31 +03:00
-- Destroy portal if pos (portal frame or portal node) got destroyed
local destroy_portal = function ( pos )
-- Deactivate Nether portal
local meta = minetest.get_meta ( pos )
2017-08-17 04:43:26 +03:00
local p1 = minetest.string_to_pos ( meta : get_string ( " portal_frame1 " ) )
local p2 = minetest.string_to_pos ( meta : get_string ( " portal_frame2 " ) )
2017-08-17 04:27:31 +03:00
if not p1 or not p2 then
return
end
local first = true
-- p1 metadata of first node
local mp1
for x = p1.x , p2.x do
for y = p1.y , p2.y do
for z = p1.z , p2.z do
local p = vector.new ( x , y , z )
local m = minetest.get_meta ( p )
if first then
--[[ Only proceed if the first node still has metadata.
If it doesn ' t have metadata, another node propably triggred the delection
routine earlier , so we bail out earlier to avoid an infinite cascade
of on_destroy events . ] ]
2017-08-17 04:43:26 +03:00
mp1 = minetest.string_to_pos ( m : get_string ( " portal_frame1 " ) )
2017-08-17 04:27:31 +03:00
if not mp1 then
return
end
end
local nn = minetest.get_node ( p ) . name
2017-11-21 06:39:27 +02:00
if nn == " mcl_portals:portal_end " then
2017-08-17 04:27:31 +03:00
-- Remove portal nodes, but not myself
if nn == " mcl_portals:portal_end " and not vector.equals ( p , pos ) then
minetest.remove_node ( p )
end
-- Clear metadata of portal nodes and the frame
2017-08-17 04:43:26 +03:00
m : set_string ( " portal_frame1 " , " " )
m : set_string ( " portal_frame2 " , " " )
m : set_string ( " portal_target " , " " )
2017-08-17 04:27:31 +03:00
end
first = false
end
end
end
end
2017-11-21 06:39:27 +02:00
-- End portal
2017-08-17 01:16:29 +03:00
minetest.register_node ( " mcl_portals:portal_end " , {
description = " End Portal " ,
2017-08-17 19:41:58 +03:00
_doc_items_longdesc = " An End portal teleports creatures and objects to the mysterious End dimension (and back!). " ,
2017-11-21 08:39:56 +02:00
_doc_items_usagehelp = " Stand in the portal for a moment to activate the teleportation. Entering an End portal in the overworld teleports you to a fixed position in the End dimension and creates a 5× 5 obsidian platform at your destination. End portals in the End will lead back to your spawn point in the Overworld. " ,
2017-08-17 01:16:29 +03:00
tiles = {
{
name = " mcl_portals_end_portal.png " ,
animation = {
type = " vertical_frames " ,
aspect_w = 16 ,
aspect_h = 16 ,
2017-09-02 15:45:05 +03:00
length = 1.0 ,
2017-08-17 01:16:29 +03:00
} ,
} ,
2017-11-21 06:39:27 +02:00
" blank.png " ,
" blank.png " ,
" blank.png " ,
" blank.png " ,
" blank.png " ,
2017-08-17 01:16:29 +03:00
} ,
drawtype = " nodebox " ,
paramtype = " light " ,
sunlight_propagates = true ,
use_texture_alpha = true ,
walkable = false ,
diggable = false ,
pointable = false ,
buildable_to = false ,
is_ground_content = false ,
drop = " " ,
-- This is 15 in MC.
light_source = 14 ,
post_effect_color = { a = 192 , r = 0 , g = 0 , b = 0 } ,
alpha = 192 ,
node_box = {
type = " fixed " ,
fixed = {
2017-11-21 06:39:27 +02:00
{ - 0.5 , - 0.5 , - 0.5 , 0.5 , 4 / 16 , 0.5 } ,
2017-08-17 01:16:29 +03:00
} ,
} ,
2017-08-17 04:27:31 +03:00
groups = { not_in_creative_inventory = 1 } ,
on_destruct = destroy_portal ,
_mcl_hardness = - 1 ,
_mcl_blast_resistance = 18000000 ,
2017-08-17 01:16:29 +03:00
} )
2017-11-21 06:39:27 +02:00
local function build_end_portal_destination ( pos )
local p1 = { x = pos.x - 2 , y = pos.y , z = pos.z - 2 }
local p2 = { x = pos.x + 2 , y = pos.y + 2 , z = pos.z + 2 }
2017-08-17 01:16:29 +03:00
for x = p1.x , p2.x do
for y = p1.y , p2.y do
2017-11-21 06:39:27 +02:00
for z = p1.z , p2.z do
local newp = { x = x , y = y , z = z }
-- Build obsidian platform
if minetest.registered_nodes [ minetest.get_node ( newp ) . name ] . is_ground_content then
if y == p1.y then
minetest.set_node ( newp , { name = " mcl_core:obsidian " } )
else
minetest.remove_node ( newp )
2017-08-17 01:16:29 +03:00
end
end
end
end
2017-08-17 02:09:32 +03:00
end
2017-08-17 01:16:29 +03:00
end
local function move_check2 ( 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
2017-09-02 20:15:15 +03:00
if minetest.get_node ( p ) . name ~= fake_portal_frame then
2017-08-17 01:16:29 +03:00
return false
end
2017-08-17 05:36:08 +03:00
-- Abort if any of the portal frame blocks already has metadata.
-- This mod does not yet portals which neighbor each other directly.
-- TODO: Reorganize the way how portal frame coordinates are stored.
local meta = minetest.get_meta ( p )
local p1 = meta : get_string ( " portal_frame1 " )
if minetest.string_to_pos ( p1 ) ~= nil then
return false
end
2017-08-17 01:16:29 +03:00
end
return true
end
local function check_end_portal ( p1 , p2 )
if p1.x ~= p2.x then
if not move_check2 ( p1 , p2.x , " x " ) then
return false
end
if not move_check2 ( p2 , p1.x , " x " ) then
return false
end
elseif p1.z ~= p2.z then
if not move_check2 ( p1 , p2.z , " z " ) then
return false
end
if not move_check2 ( p2 , p1.z , " z " ) then
return false
end
else
return false
end
if not move_check2 ( p1 , p2.y , " y " ) then
return false
end
if not move_check2 ( p2 , p1.y , " y " ) then
return false
end
return true
end
local function is_end_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_end_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_end_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_end_portal ( pos )
local p1 , p2 = is_end_portal ( pos )
if not p1 or not p2 then
return false
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
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 = " mcl_portals:portal_end " , param2 = param2 } )
end
local meta = minetest.get_meta ( p )
2017-08-17 04:43:26 +03:00
-- Portal frame corners
meta : set_string ( " portal_frame1 " , minetest.pos_to_string ( p1 ) )
meta : set_string ( " portal_frame2 " , minetest.pos_to_string ( p2 ) )
-- Portal target coordinates
meta : set_string ( " portal_target " , minetest.pos_to_string ( target3 ) )
2017-08-17 01:16:29 +03:00
end
end
return true
end
minetest.register_abm ( {
label = " End portal teleportation " ,
nodenames = { " mcl_portals:portal_end " } ,
interval = 1 ,
2017-11-21 06:39:27 +02:00
chance = 1 ,
2017-08-17 01:16:29 +03:00
action = function ( pos , node )
2017-11-21 06:39:27 +02:00
-- Destroy legacy end portals created with quartz block frame
-- by turning them into cobwebs.
-- We can tell if a end portal is legacy if it has portal_target as metadata.
-- FIXME: Remove this after some time.
local meta = minetest.get_meta ( pos )
2017-11-21 08:26:45 +02:00
local legacy_portal_target = meta : get_string ( " portal_frame1 " )
2017-11-21 06:39:27 +02:00
if legacy_portal_target and legacy_portal_target ~= " " then
minetest.set_node ( pos , { name = " mcl_core:cobweb " } )
return
end
for _ , obj in ipairs ( minetest.get_objects_inside_radius ( pos , 1 ) ) do
local lua_entity = obj : get_luaentity ( ) --maikerumine added for objects to travel
2017-08-17 01:16:29 +03:00
if obj : is_player ( ) or lua_entity then
2017-11-21 06:39:27 +02:00
local _ , dim = mcl_util.y_to_layer ( pos.y )
local target
if dim == " end " then
-- End portal in the End:
-- Teleport back to the player's spawn in the Overworld.
-- TODO: Implement better spawn point detection
target = minetest.string_to_pos ( obj : get_attribute ( " mcl_beds:spawn " ) )
if not target then
target = minetest.setting_get_pos ( " static_spawnpoint " )
end
if not target then
target = { x = 0 , y = 0 , z = 0 }
2017-11-21 06:57:08 +02:00
if mg_name == " flat " then
target.y = mcl_vars.mg_bedrock_overworld_max + 5
end
2017-08-17 01:16:29 +03:00
end
2017-11-21 06:39:27 +02:00
else
-- End portal in any other dimension:
-- Teleport to the End at a fixed position and generate a
-- 5× 5 obsidian platform below.
local platform_pos = mcl_vars.mg_end_platform_pos
-- force emerge of target1 area
minetest.get_voxel_manip ( ) : read_from_map ( platform_pos , platform_pos )
if not minetest.get_node_or_nil ( platform_pos ) then
minetest.emerge_area ( vector.subtract ( platform_pos , 3 ) , vector.add ( platform_pos , 3 ) )
end
local objpos = obj : getpos ( )
if objpos == nil then
return
end
-- If player stands, player is at ca. something+0.5
-- which might cause precision problems, so we used ceil.
objpos.y = math.ceil ( objpos.y )
if minetest.get_node ( objpos ) . name ~= " mcl_portals:portal_end " then
return
end
-- Build destination
local function check_and_build_end_portal_destination ( pos )
local n = minetest.get_node_or_nil ( pos )
if n and n.name ~= " mcl_core:obsidian " then
build_end_portal_destination ( pos )
minetest.after ( 2 , check_and_build_end_portal_destination , pos )
elseif not n then
minetest.after ( 1 , check_and_build_end_portal_destination , pos )
end
end
local platform
check_and_build_end_portal_destination ( platform_pos )
2017-08-17 02:33:36 +03:00
2017-11-21 06:39:27 +02:00
target = table.copy ( platform_pos )
target.y = target.y + 1
2017-08-17 01:16:29 +03:00
end
2017-11-21 06:39:27 +02:00
-- Teleport
obj : set_pos ( target )
2017-11-21 08:24:56 +02:00
if obj : is_player ( ) then
-- Look towards the End island
if dim ~= " end " then
obj : set_look_horizontal ( math.pi / 2 )
end
2017-11-21 07:03:07 +02:00
minetest.sound_play ( " mcl_portals_teleport " , { pos = target , gain = 0.5 , max_hear_distance = 16 } )
2017-11-21 06:39:27 +02:00
end
2017-08-17 01:16:29 +03:00
end
end
end ,
} )
--[[ ITEM OVERRIDES ]]
2017-09-02 16:49:41 +03:00
-- End Portal Frame (TODO)
minetest.register_node ( " mcl_portals:end_portal_frame " , {
description = " End Portal Frame " ,
groups = { creative_breakable = 1 , deco_block = 1 } ,
2017-09-02 17:16:04 +03:00
tiles = { " mcl_portals_endframe_top.png " , " mcl_portals_endframe_bottom.png " , " mcl_portals_endframe_side.png " } ,
2017-09-02 16:49:41 +03:00
paramtype2 = " facedir " ,
drawtype = " nodebox " ,
node_box = {
type = " fixed " ,
fixed = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 5 / 16 , 0.5 } ,
} ,
is_ground_content = false ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
paramtype = " light " ,
sunlight_propagates = false ,
light_source = 1 ,
_mcl_blast_resistance = 18000000 ,
_mcl_hardness = - 1 ,
} )
minetest.register_node ( " mcl_portals:end_portal_frame_eye " , {
description = " End Portal Frame with Eye of Ender " ,
_doc_items_create_entry = false ,
groups = { creative_breakable = 1 , not_in_creative_inventory = 1 } ,
2017-09-02 17:16:04 +03:00
tiles = { " mcl_portals_endframe_top.png^[lowpart:75:mcl_portals_endframe_eye.png " , " mcl_portals_endframe_bottom.png " , " mcl_portals_endframe_eye.png^mcl_portals_endframe_side.png " } ,
2017-09-02 16:49:41 +03:00
paramtype2 = " facedir " ,
drawtype = " nodebox " ,
node_box = {
type = " fixed " ,
fixed = {
{ - 0.5 , - 0.5 , - 0.5 , 0.5 , 5 / 16 , 0.5 } , -- Frame
{ - 4 / 16 , 5 / 16 , - 4 / 16 , 4 / 16 , 0.5 , 4 / 16 } , -- Eye
} ,
} ,
is_ground_content = false ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
paramtype = " light " ,
sunlight_propagates = false ,
light_source = 1 ,
_mcl_blast_resistance = 18000000 ,
_mcl_hardness = - 1 ,
2017-09-02 17:28:14 +03:00
-- TODO: Destroy end portal if this block got destroyed
2017-09-02 16:49:41 +03:00
} )
if minetest.get_modpath ( " doc " ) then
doc.add_entry_alias ( " nodes " , " mcl_portals:end_portal_frame " , " nodes " , " mcl_portals:end_portal_frame_eye " )
end
2017-08-17 01:16:29 +03:00
-- Portal opener
minetest.override_item ( " mcl_end:ender_eye " , {
2017-08-17 20:05:13 +03:00
_doc_items_longdesc = " An eye of ender can be used to open End portals. " ,
2017-11-21 06:39:27 +02:00
-- TODO: _doc_items_usagehelp = ,
2017-08-17 01:16:29 +03:00
on_place = function ( itemstack , user , pointed_thing )
2017-08-17 05:12:34 +03:00
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node ( pointed_thing.under )
if user and not user : get_player_control ( ) . sneak then
if minetest.registered_nodes [ node.name ] and minetest.registered_nodes [ node.name ] . on_rightclick then
return minetest.registered_nodes [ node.name ] . on_rightclick ( pointed_thing.under , node , user , itemstack ) or itemstack
2017-08-17 04:27:31 +03:00
end
2017-08-17 05:12:34 +03:00
end
-- If used on portal frame, open a portal
2017-09-02 20:15:15 +03:00
-- FIXME: This is the fake portal. Remove when the real end portal frame works
if pointed_thing.under and node.name == fake_portal_frame then
2017-08-17 05:12:34 +03:00
local opened = make_end_portal ( pointed_thing.under )
if opened then
if minetest.get_modpath ( " doc " ) then
doc.mark_entry_as_revealed ( user : get_player_name ( ) , " nodes " , " mcl_portals:portal_end " )
end
minetest.sound_play (
" fire_flint_and_steel " ,
{ pos = pointed_thing.above , gain = 0.5 , max_hear_distance = 16 } )
if not minetest.settings : get_bool ( " creative_mode " ) then
itemstack : take_item ( ) -- 1 use
end
2017-08-17 02:11:06 +03:00
end
2017-08-17 01:16:29 +03:00
2017-09-02 20:15:15 +03:00
-- Place eye of ender into end portal frame
elseif pointed_thing.under and node.name == " mcl_portals:end_portal_frame " then
-- TODO: Open real end portal
minetest.swap_node ( pointed_thing.under , { name = " mcl_portals:end_portal_frame_eye " , param2 = node.param2 } )
if minetest.get_modpath ( " doc " ) then
doc.mark_entry_as_revealed ( user : get_player_name ( ) , " nodes " , " mcl_portals:end_portal_frame " )
end
minetest.sound_play (
" default_place_node_hard " ,
{ pos = pointed_thing.under , gain = 0.5 , max_hear_distance = 16 } )
if not minetest.settings : get_bool ( " creative_mode " ) then
itemstack : take_item ( ) -- 1 use
end
end
2017-08-17 01:16:29 +03:00
return itemstack
end ,
} )