MineClone5/mods/ITEMS/mcl_portals/portal_end.lua

386 lines
12 KiB
Lua
Raw Normal View History

-- Parameters
2017-08-18 02:42:26 +02:00
local SPAWN_MIN = mcl_vars.mg_end_min+70
local SPAWN_MAX = mcl_vars.mg_end_min+98
local mg_name = minetest.get_mapgen_setting("mg_name")
2017-11-21 05:39:27 +01:00
-- End portal
minetest.register_node("mcl_portals:portal_end", {
description = "End Portal",
2017-08-17 18:41:58 +02:00
_doc_items_longdesc = "An End portal teleports creatures and objects to the mysterious End dimension (and back!).",
2017-11-21 09:54:45 +01:00
_doc_items_usagehelp = "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.",
tiles = {
{
name = "mcl_portals_end_portal.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
2017-11-21 05:39:27 +01:00
"blank.png",
"blank.png",
"blank.png",
"blank.png",
"blank.png",
},
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 05:39:27 +01:00
{-0.5, -0.5, -0.5, 0.5, 4/16, 0.5},
},
},
2017-08-17 03:27:31 +02:00
groups = {not_in_creative_inventory = 1},
_mcl_hardness = -1,
_mcl_blast_resistance = 18000000,
})
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}
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)
end
end
end
end
2017-08-17 01:09:32 +02:00
end
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)
-- Check if pos has an end portal frame with eye of ender
local eframe = function(pos, param2)
local node = minetest.get_node(pos)
if node.name == "mcl_portals:end_portal_frame_eye" then
if param2 == nil or node.param2 == param2 then
return true, node
end
end
2017-11-21 09:54:45 +01:00
return false
end
2017-11-21 09:54:45 +01:00
-- Step 1: Find a row of 3 end portal frames with eyes, all facing the same direction
local streak = 0
local streak_start, streak_end, streak_start_node, streak_end_node
local last_param2
local axes = { "x", "z" }
for a=1, #axes do
local axis = axes[a]
for b=pos[axis]-2, pos[axis]+2 do
local cpos = table.copy(pos)
cpos[axis] = b
local e, node = eframe(cpos, last_param2)
if e then
last_param2 = node.param2
streak = streak + 1
if streak == 1 then
streak_start = table.copy(pos)
streak_start[axis] = b
streak_start_node = node
elseif streak == 3 then
streak_end = table.copy(pos)
streak_end[axis] = b
streak_end_node = node
break
end
else
streak = 0
last_param2 = nil
end
end
2017-11-21 09:54:45 +01:00
if streak_end then
break
end
2017-11-21 09:54:45 +01:00
streak = 0
last_param2 = nil
end
2017-11-21 09:54:45 +01:00
-- Has a row been found?
if streak_end then
-- Step 2: Using the known facedir, check the remaining spots in which we expect
-- “eyed” end portal frames.
local dir = minetest.facedir_to_dir(streak_start_node.param2)
if dir.x ~= 0 then
for i=1, 3 do
if not eframe({x=streak_start.x + i*dir.x, y=streak_start.y, z=streak_start.z - 1}) then
return false
end
if not eframe({x=streak_start.x + i*dir.x, y=streak_start.y, z=streak_end.z + 1}) then
return false
end
if not eframe({x=streak_start.x + 4*dir.x, y=streak_start.y, z=streak_start.z + i-1}) then
return false
end
end
2017-11-21 09:54:45 +01:00
-- All checks survived! We have a valid portal!
if dir.x > 0 then
k = 1
else
k = -3
end
2017-11-21 09:54:45 +01:00
return true, { x = streak_start.x + k, y = streak_start.y, z = streak_start.z }
elseif dir.z ~= 0 then
for i=1, 3 do
if not eframe({x=streak_start.x - 1, y=streak_start.y, z=streak_start.z + i*dir.z}) then
return false
end
if not eframe({x=streak_end.x + 1, y=streak_start.y, z=streak_start.z + i*dir.z}) then
return false
end
if not eframe({x=streak_start.x + i-1, y=streak_start.y, z=streak_start.z + 4*dir.z}) then
return false
end
end
if dir.z > 0 then
k = 1
else
k = -3
end
-- All checks survived! We have a valid portal!
return true, { x = streak_start.x, y = streak_start.y, z = streak_start.z + k }
end
end
2017-11-21 09:54:45 +01:00
return false
end
-- 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
local name
if destroy then
name = "air"
else
name = "mcl_portals:portal_end"
end
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
minetest.set_node({x=x,y=pos.y,z=z}, {name=name})
end
end
end
minetest.register_abm({
label = "End portal teleportation",
nodenames = {"mcl_portals:portal_end"},
interval = 1,
2017-11-21 05:39:27 +01:00
chance = 1,
action = function(pos, node)
2017-11-21 05:39:27 +01: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 07:26:45 +01:00
local legacy_portal_target = meta:get_string("portal_frame1")
2017-11-21 05:39:27 +01: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
if obj:is_player() or lua_entity then
local dim = mcl_worlds.pos_to_dimension(pos)
2017-11-21 05:39:27 +01:00
2017-11-21 22:58:11 +01:00
local objpos = obj:getpos()
if objpos == nil then
return
end
-- 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
end
2017-11-21 05:39:27 +01:00
local target
if dim == "end" then
-- End portal in the End:
-- Teleport back to the player's spawn in the Overworld.
2017-11-24 07:04:03 +01:00
target = mcl_spawn.get_spawn_pos(obj)
2017-11-21 05:39:27 +01: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
-- 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
2017-11-21 05:39:27 +01:00
end
local platform
build_end_portal_destination(platform_pos)
2017-11-21 05:39:27 +01:00
check_and_build_end_portal_destination(platform_pos)
2017-08-17 01:33:36 +02:00
2017-11-21 05:39:27 +01:00
target = table.copy(platform_pos)
target.y = target.y + 1
end
2017-11-21 05:39:27 +01:00
-- Teleport
obj:set_pos(target)
if obj:is_player() then
-- Look towards the main End island
if dim ~= "end" then
obj:set_look_horizontal(math.pi/2)
end
mcl_worlds.dimension_change(obj, mcl_worlds.pos_to_dimension(target))
2017-11-21 06:03:07 +01:00
minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16})
2017-11-21 05:39:27 +01:00
end
end
end
end,
})
local rotate_frame, rotate_frame_eye
if minetest.get_modpath("screwdriver") then
rotate_frame = screwdriver.rotate_simple
-- TODO: Make the other node rotatable as well.
-- Problem: We need to capture edge cases and update the portal accordingly.
rotate_frame_eye = false
end
2017-09-02 15:49:41 +02:00
minetest.register_node("mcl_portals:end_portal_frame", {
description = "End Portal Frame",
2017-11-21 09:54:45 +01:00
_doc_items_longdesc = "End portal frames are used in the construction of End portals. Each block has a socket for an eye of ender.",
_doc_items_usagehelp = "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" .. "Place an eye of ender into each block. The end portal appears in the middle after placing the final eye." .. "\n" .. "Once placed, an eye of ender can not be taken back.",
2017-09-02 15:49:41 +02:00
groups = { creative_breakable = 1, deco_block = 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" },
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,
on_rotate = rotate_frame,
2017-09-02 15:49:41 +02:00
_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 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" },
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,
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,
2017-09-02 15:49:41 +02:00
_mcl_blast_resistance = 18000000,
_mcl_hardness = -1,
})
if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", "mcl_portals:end_portal_frame", "nodes", "mcl_portals:end_portal_frame_eye")
end
--[[ ITEM OVERRIDES ]]
-- Portal opener
minetest.override_item("mcl_end:ender_eye", {
2017-11-21 09:54:45 +01:00
_doc_items_longdesc = "Eye of ender can be used in the construction of End portal frames.",
_doc_items_usagehelp = "Find a structure with 12 end portal frames surrounding a horizontal aread of 3×3 blocks, with each block facing inward. Place an eye of ender into each end portal frame to create the portal.",
on_place = function(itemstack, user, pointed_thing)
-- 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
end
-- 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
minetest.swap_node(pointed_thing.under, { name = "mcl_portals:end_portal_frame_eye", param2 = node.param2 })
2017-11-21 09:54:45 +01:00
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
2017-11-21 09:54:45 +01:00
local ok, ppos = check_end_portal_frame(pointed_thing.under)
if ok then
end_portal_area(ppos)
2017-11-21 09:54:45 +01:00
if minetest.get_modpath("doc") then
doc.mark_entry_as_revealed(user:get_player_name(), "nodes", "mcl_portals:portal_end")
end
end
end
return itemstack
end,
})