2021-05-29 16:12:33 +02:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2019-03-08 00:22:28 +01:00
2021-05-22 23:07:56 +02:00
local table = table
local vector = vector
local math = math
2021-07-22 00:46:43 +02:00
local has_doc = minetest.get_modpath ( " doc " )
2021-05-29 16:12:33 +02:00
local function destroy_portal ( pos )
2020-01-06 16:49:22 +01:00
local neighbors = {
{ x = 1 , y = 0 , z = 0 } ,
{ x =- 1 , y = 0 , z = 0 } ,
{ x = 0 , y = 0 , z = 1 } ,
{ x = 0 , y = 0 , z =- 1 } ,
}
for n = 1 , # neighbors do
local npos = vector.add ( pos , neighbors [ n ] )
if minetest.get_node ( npos ) . name == " mcl_portals:portal_end " then
minetest.remove_node ( npos )
end
end
end
2021-01-16 15:51:30 +01:00
local ep_scheme = {
2021-01-21 15:35:04 +01:00
{ o = { x = 0 , y = 0 , z = 1 } , p = 1 } ,
{ o = { x = 0 , y = 0 , z = 2 } , p = 1 } ,
{ o = { x = 0 , y = 0 , z = 3 } , p = 1 } ,
{ o = { x = 1 , y = 0 , z = 4 } , p = 2 } ,
{ o = { x = 2 , y = 0 , z = 4 } , p = 2 } ,
{ o = { x = 3 , y = 0 , z = 4 } , p = 2 } ,
{ o = { x = 4 , y = 0 , z = 3 } , p = 3 } ,
{ o = { x = 4 , y = 0 , z = 2 } , p = 3 } ,
{ o = { x = 4 , y = 0 , z = 1 } , p = 3 } ,
{ o = { x = 3 , y = 0 , z = 0 } , p = 0 } ,
{ o = { x = 2 , y = 0 , z = 0 } , p = 0 } ,
{ o = { x = 1 , y = 0 , z = 0 } , p = 0 } ,
2021-01-16 15:51:30 +01:00
}
2017-11-21 05:39:27 +01:00
-- End portal
2017-08-17 00:16:29 +02:00
minetest.register_node ( " mcl_portals:portal_end " , {
2019-03-08 00:22:28 +01:00
description = S ( " End Portal " ) ,
2020-02-19 04:54:17 +01:00
_tt_help = S ( " Used to construct end portals " ) ,
2019-03-08 00:22:28 +01:00
_doc_items_longdesc = S ( " An End portal teleports creatures and objects to the mysterious End dimension (and back!). " ) ,
_doc_items_usagehelp = S ( " Hop into the portal to teleport. 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 00:16:29 +02:00
tiles = {
{
name = " mcl_portals_end_portal.png " ,
animation = {
type = " vertical_frames " ,
aspect_w = 16 ,
aspect_h = 16 ,
2017-09-02 14:45:05 +02:00
length = 1.0 ,
2017-08-17 00:16:29 +02:00
} ,
} ,
2018-05-16 19:22:55 +02:00
{
name = " mcl_portals_end_portal.png " ,
animation = {
type = " vertical_frames " ,
aspect_w = 16 ,
aspect_h = 16 ,
length = 6.0 ,
} ,
} ,
2017-11-21 05:39:27 +01:00
" blank.png " ,
2017-08-17 00:16:29 +02:00
} ,
drawtype = " nodebox " ,
paramtype = " light " ,
sunlight_propagates = true ,
2021-02-18 10:39:19 +01:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " blend " or true ,
2021-01-16 15:51:30 +01:00
walkable = false ,
2017-08-17 00:16:29 +02:00
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 } ,
2020-01-06 16:49:22 +01:00
after_destruct = destroy_portal ,
2018-05-16 19:22:55 +02:00
-- This prevents “falling through”
collision_box = {
type = " fixed " ,
fixed = {
{ - 0.5 , - 0.5 , - 0.5 , 0.5 , - 7 / 16 , 0.5 } ,
} ,
} ,
2017-08-17 00:16:29 +02:00
node_box = {
type = " fixed " ,
fixed = {
2017-11-21 05:39:27 +01:00
{ - 0.5 , - 0.5 , - 0.5 , 0.5 , 4 / 16 , 0.5 } ,
2017-08-17 00:16:29 +02:00
} ,
} ,
2019-12-13 10:20:08 +01:00
groups = { portal = 1 , not_in_creative_inventory = 1 , disable_jump = 1 } ,
2017-08-17 03:27:31 +02:00
_mcl_hardness = - 1 ,
2020-04-17 21:40:13 +02:00
_mcl_blast_resistance = 36000000 ,
2017-08-17 00:16:29 +02:00
} )
2017-11-21 09:54:45 +01:00
-- Obsidian platform at the End portal destination in the End
2017-11-21 05:39:27 +01: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 00:16:29 +02:00
for x = p1.x , p2.x do
for y = p1.y , p2.y do
2017-11-21 05:39:27 +01: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 00:16:29 +02:00
end
end
end
end
2017-08-17 01:09:32 +02:00
end
2017-08-17 00:16:29 +02:00
end
2017-11-21 09:54:45 +01:00
-- Check if pos is part of a valid end portal frame, filled with eyes of ender.
local function check_end_portal_frame ( pos )
2021-01-16 15:51:30 +01:00
for i = 1 , 12 do
local pos0 = vector.subtract ( pos , ep_scheme [ i ] . o )
local portal = true
for j = 1 , 12 do
local p = vector.add ( pos0 , ep_scheme [ j ] . o )
local node = minetest.get_node ( p )
if not node or node.name ~= " mcl_portals:end_portal_frame_eye " or node.param2 ~= ep_scheme [ j ] . p then
portal = false
break
2017-11-21 09:54:45 +01:00
end
2017-08-17 00:16:29 +02:00
end
2021-01-16 15:51:30 +01:00
if portal then
return true , { x = pos0.x + 1 , y = pos0.y , z = pos0.z + 1 }
2017-08-17 00:16:29 +02:00
end
end
2017-11-21 09:54:45 +01:00
return false
2017-08-17 00:16:29 +02:00
end
2017-12-09 14:58:06 +01:00
-- Generate or destroy a 3× 3 end portal beginning at pos. To be used to fill an end portal framea.
-- If destroy == true, the 3× 3 area is removed instead.
local function end_portal_area ( pos , destroy )
2017-11-21 09:54:45 +01:00
local SIZE = 3
2017-12-09 14:58:06 +01:00
local name
if destroy then
name = " air "
else
name = " mcl_portals:portal_end "
end
2020-01-06 16:51:40 +01:00
local posses = { }
2017-11-21 09:54:45 +01:00
for x = pos.x , pos.x + SIZE - 1 do
for z = pos.z , pos.z + SIZE - 1 do
2020-01-06 16:51:40 +01:00
table.insert ( posses , { x = x , y = pos.y , z = z } )
2017-08-17 00:16:29 +02:00
end
end
2020-01-06 16:51:40 +01:00
minetest.bulk_set_node ( posses , { name = name } )
2017-08-17 00:16:29 +02:00
end
2021-01-16 15:51:30 +01:00
function mcl_portals . end_teleport ( obj , pos )
if not obj then return end
local pos = pos or obj : get_pos ( )
if not pos then return end
local dim = mcl_worlds.pos_to_dimension ( pos )
2017-11-21 05:39:27 +01:00
2021-01-16 15:51:30 +01:00
local target
if dim == " end " then
-- End portal in the End:
-- Teleport back to the player's spawn or world spawn in the Overworld.
if obj : is_player ( ) then
target = mcl_spawn.get_player_spawn_pos ( obj )
end
2017-11-21 22:58:11 +01:00
2021-01-16 15:51:30 +01:00
target = target or mcl_spawn.get_world_spawn_pos ( obj )
else
-- End portal in any other dimension:
-- Teleport to the End at a fixed position and generate a
-- 5× 5 obsidian platform below.
2017-11-21 22:58:11 +01:00
2021-04-28 22:53:48 +02:00
local platform_pos = mcl_mapgen.end_ . platform_pos
2021-01-16 15:51:30 +01:00
-- 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
2021-01-06 13:01:27 +01:00
2021-01-16 15:51:30 +01:00
-- 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
2017-11-21 05:39:27 +01:00
2021-01-16 15:51:30 +01:00
build_end_portal_destination ( platform_pos )
check_and_build_end_portal_destination ( platform_pos )
2017-11-21 05:39:27 +01:00
2021-01-16 15:51:30 +01:00
target = table.copy ( platform_pos )
target.y = target.y + 1
end
2017-11-21 05:39:27 +01:00
2021-01-16 15:51:30 +01:00
-- Teleport
obj : set_pos ( target )
2017-08-17 01:33:36 +02:00
2021-01-16 15:51:30 +01:00
if obj : is_player ( ) then
-- Look towards the main End island
if dim ~= " end " then
obj : set_look_horizontal ( math.pi / 2 )
2021-04-04 19:13:46 +02:00
-- Show credits
else
mcl_credits.show ( obj )
2021-01-16 15:51:30 +01:00
end
mcl_worlds.dimension_change ( obj , mcl_worlds.pos_to_dimension ( target ) )
minetest.sound_play ( " mcl_portals_teleport " , { pos = target , gain = 0.5 , max_hear_distance = 16 } , true )
end
end
2017-11-21 05:39:27 +01:00
2021-01-16 15:51:30 +01:00
function mcl_portals . end_portal_teleport ( pos , node )
2021-03-16 17:39:06 +01:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( pos , 1 ) ) do
2021-01-16 15:51:30 +01:00
local lua_entity = obj : get_luaentity ( ) --maikerumine added for objects to travel
if obj : is_player ( ) or lua_entity then
local objpos = obj : get_pos ( )
if objpos == nil then
return
end
2021-01-06 13:01:27 +01:00
2021-01-16 15:51:30 +01:00
-- Check if object is actually in portal.
objpos.y = math.ceil ( objpos.y )
if minetest.get_node ( objpos ) . name ~= " mcl_portals:portal_end " then
return
2017-08-17 00:16:29 +02:00
end
2021-01-16 15:51:30 +01:00
mcl_portals.end_teleport ( obj , objpos )
2022-03-29 20:49:39 +02:00
awards.unlock ( obj : get_player_name ( ) , " mcl:enterEndPortal " )
2021-01-16 15:51:30 +01:00
2017-08-17 00:16:29 +02:00
end
2021-01-16 15:51:30 +01:00
end
end
minetest.register_abm ( {
label = " End portal teleportation " ,
nodenames = { " mcl_portals:portal_end " } ,
2022-04-04 03:02:10 +02:00
interval = 1 ,
2021-01-16 15:51:30 +01:00
chance = 1 ,
2022-04-04 03:02:10 +02:00
-- TODO: Move to playerinfo/playerplus/mob api
2021-01-16 15:51:30 +01:00
action = mcl_portals.end_portal_teleport ,
2017-08-17 00:16:29 +02:00
} )
2017-12-09 14:58:06 +01:00
local rotate_frame , rotate_frame_eye
2017-08-17 00:16:29 +02:00
2017-12-09 14:58:06 +01:00
if minetest.get_modpath ( " screwdriver " ) then
2017-12-09 15:01:41 +01:00
-- Intentionally not rotatable
rotate_frame = false
2017-12-09 14:58:06 +01:00
rotate_frame_eye = false
end
2017-08-17 00:16:29 +02:00
2021-01-21 15:35:04 +01:00
local function after_place_node ( pos , placer , itemstack , pointed_thing )
local node = minetest.get_node ( pos )
if node then
node.param2 = ( node.param2 + 2 ) % 4
minetest.swap_node ( pos , node )
local ok , ppos = check_end_portal_frame ( pos )
if ok then
-- Epic 'portal open' sound effect that can be heard everywhere
minetest.sound_play ( " mcl_portals_open_end_portal " , { gain = 0.8 } , true )
end_portal_area ( ppos )
end
end
end
2017-09-02 15:49:41 +02:00
minetest.register_node ( " mcl_portals:end_portal_frame " , {
2019-03-08 00:22:28 +01:00
description = S ( " End Portal Frame " ) ,
2020-02-19 04:54:17 +01:00
_tt_help = S ( " Used to construct end portals " ) ,
2019-03-25 12:05:57 +01:00
_doc_items_longdesc = S ( " End portal frames are used in the construction of End portals. Each block has a socket for an eye of ender. " ) .. " \n " .. S ( " NOTE: The End dimension is currently incomplete and might change in future versions. " ) ,
_doc_items_usagehelp = S ( " To create an End portal, you need 12 end portal frames and 12 eyes of ender. The end portal frames have to be arranged around a horizontal 3× 3 area with each block facing inward. Any other arrangement will fail. " ) .. " \n " .. S ( " Place an eye of ender into each block. The end portal appears in the middle after placing the final eye. " ) .. " \n " .. S ( " Once placed, an eye of ender can not be taken back. " ) ,
2019-12-13 10:20:08 +01:00
groups = { creative_breakable = 1 , deco_block = 1 , end_portal_frame = 1 } ,
2017-09-02 16:16:04 +02:00
tiles = { " mcl_portals_endframe_top.png " , " mcl_portals_endframe_bottom.png " , " mcl_portals_endframe_side.png " } ,
2021-02-18 14:00:17 +01:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-09-02 15:49:41 +02: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 ,
2017-12-09 14:58:06 +01:00
on_rotate = rotate_frame ,
2021-01-21 15:35:04 +01:00
after_place_node = after_place_node ,
2020-04-17 21:40:13 +02:00
_mcl_blast_resistance = 36000000 ,
2017-09-02 15:49:41 +02:00
_mcl_hardness = - 1 ,
} )
minetest.register_node ( " mcl_portals:end_portal_frame_eye " , {
2019-03-08 00:22:28 +01:00
description = S ( " End Portal Frame with Eye of Ender " ) ,
2020-03-08 03:18:47 +01:00
_tt_help = S ( " Used to construct end portals " ) ,
2017-09-02 15:49:41 +02:00
_doc_items_create_entry = false ,
2021-06-15 19:37:03 +02:00
groups = { creative_breakable = 1 , deco_block = 1 , comparator_signal = 15 , end_portal_frame = 2 , not_in_creative_inventory = 1 } ,
2017-09-02 16:16:04 +02: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 " } ,
2021-02-18 14:00:17 +01:00
use_texture_alpha = minetest.features . use_texture_alpha_string_modes and " opaque " or false ,
2017-09-02 15:49:41 +02: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 ,
2017-12-09 14:58:06 +01:00
on_destruct = function ( pos )
local ok , ppos = check_end_portal_frame ( pos )
if ok then
end_portal_area ( ppos , true )
end
end ,
on_rotate = rotate_frame_eye ,
2021-01-21 15:35:04 +01:00
after_place_node = after_place_node ,
2020-04-17 21:40:13 +02:00
_mcl_blast_resistance = 36000000 ,
2017-09-02 15:49:41 +02:00
_mcl_hardness = - 1 ,
} )
2021-07-22 00:46:43 +02:00
if has_doc then
2017-09-02 15:49:41 +02:00
doc.add_entry_alias ( " nodes " , " mcl_portals:end_portal_frame " , " nodes " , " mcl_portals:end_portal_frame_eye " )
end
2017-12-09 14:58:06 +01:00
--[[ ITEM OVERRIDES ]]
2017-08-17 00:16:29 +02:00
-- Portal opener
minetest.override_item ( " mcl_end:ender_eye " , {
on_place = function ( itemstack , user , pointed_thing )
2017-08-17 04:12:34 +02: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 03:27:31 +02:00
end
2017-08-17 04:12:34 +02:00
end
2017-09-02 19:15:15 +02:00
-- Place eye of ender into end portal frame
2017-11-21 09:54:45 +01:00
if pointed_thing.under and node.name == " mcl_portals:end_portal_frame " then
2019-02-08 21:59:01 +01:00
local protname = user : get_player_name ( )
if minetest.is_protected ( pointed_thing.under , protname ) then
minetest.record_protection_violation ( pointed_thing.under , protname )
return itemstack
end
2018-05-13 05:20:41 +02:00
minetest.set_node ( pointed_thing.under , { name = " mcl_portals:end_portal_frame_eye " , param2 = node.param2 } )
2017-11-21 09:54:45 +01:00
2021-07-22 00:46:43 +02:00
if has_doc then
2017-09-02 19:15:15 +02:00
doc.mark_entry_as_revealed ( user : get_player_name ( ) , " nodes " , " mcl_portals:end_portal_frame " )
end
minetest.sound_play (
" default_place_node_hard " ,
2020-04-07 00:55:45 +02:00
{ pos = pointed_thing.under , gain = 0.5 , max_hear_distance = 16 } , true )
2020-07-10 16:08:40 +02:00
if not minetest.is_creative_enabled ( user : get_player_name ( ) ) then
2017-09-02 19:15:15 +02:00
itemstack : take_item ( ) -- 1 use
end
2017-11-21 09:54:45 +01:00
2021-01-21 15:35:04 +01:00
local ok , ppos = check_end_portal_frame ( pointed_thing.under )
2017-11-21 09:54:45 +01:00
if ok then
2021-01-21 15:35:04 +01:00
-- Epic 'portal open' sound effect that can be heard everywhere
minetest.sound_play ( " mcl_portals_open_end_portal " , { gain = 0.8 } , true )
end_portal_area ( ppos )
2021-07-22 00:46:43 +02:00
if has_doc then
2017-11-21 09:54:45 +01:00
doc.mark_entry_as_revealed ( user : get_player_name ( ) , " nodes " , " mcl_portals:portal_end " )
end
end
2017-09-02 19:15:15 +02:00
end
2017-08-17 00:16:29 +02:00
return itemstack
end ,
} )