More MC-like end portal block (WIP)

This commit is contained in:
Wuzzy 2017-11-21 05:39:27 +01:00
parent 526217a21b
commit 7c15d5f9ac
3 changed files with 115 additions and 171 deletions

View File

@ -72,6 +72,8 @@ end
mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border
mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit
mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000 mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 80, z = 0 }
-- Realm barrier used to safely separate the End from the void below the Overworld -- Realm barrier used to safely separate the End from the void below the Overworld
mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max
mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11 mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11

View File

@ -18,13 +18,6 @@ local np_cave = {
octaves = 5, octaves = 5,
persist = 0.7 persist = 0.7
} }
-- Portal frame material
local fake_portal_frame = "mcl_nether:quartz_block"
-- Table of objects (including players) which recently teleported by a
-- End portal. Those objects have a brief cooloff period before they
-- can teleport again. This prevents annoying back-and-forth teleportation.
local portal_cooloff = {}
-- Destroy portal if pos (portal frame or portal node) got destroyed -- Destroy portal if pos (portal frame or portal node) got destroyed
local destroy_portal = function(pos) local destroy_portal = function(pos)
@ -56,7 +49,7 @@ local destroy_portal = function(pos)
end end
end end
local nn = minetest.get_node(p).name local nn = minetest.get_node(p).name
if nn == fake_portal_frame or nn == "mcl_portals:portal_end" then if nn == "mcl_portals:portal_end" then
-- Remove portal nodes, but not myself -- Remove portal nodes, but not myself
if nn == "mcl_portals:portal_end" and not vector.equals(p, pos) then if nn == "mcl_portals:portal_end" and not vector.equals(p, pos) then
minetest.remove_node(p) minetest.remove_node(p)
@ -72,26 +65,13 @@ local destroy_portal = function(pos)
end end
end end
-- Fake end portal -- End portal
-- TODO: Create real end portal -- TODO: Create real end portal
minetest.register_node("mcl_portals:portal_end", { minetest.register_node("mcl_portals:portal_end", {
description = "End Portal", description = "End Portal",
_doc_items_longdesc = "An End portal teleports creatures and objects to the mysterious End dimension (and back!).", _doc_items_longdesc = "An End portal teleports creatures and objects to the mysterious End dimension (and back!).",
_doc_items_usagehelp = "Stand in the portal for a moment to activate the teleportation. Entering such a portal for the first time will create a new portal in your destination. End portal which were built in the End will lead back to the Overworld. An End portal is destroyed if any of its surrounding frame blocks is destroyed.", _doc_items_usagehelp = "Stand in the portal for a moment to activate the teleportation. Entering such a portal for the first time will create a new portal in your destination. End portal which were built in the End will lead back to the Overworld. An End portal is destroyed if any of its surrounding frame blocks is destroyed.",
tiles = { tiles = {
"blank.png",
"blank.png",
"blank.png",
"blank.png",
{
name = "mcl_portals_end_portal.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
{ {
name = "mcl_portals_end_portal.png", name = "mcl_portals_end_portal.png",
animation = { animation = {
@ -101,10 +81,14 @@ minetest.register_node("mcl_portals:portal_end", {
length = 1.0, length = 1.0,
}, },
}, },
"blank.png",
"blank.png",
"blank.png",
"blank.png",
"blank.png",
}, },
drawtype = "nodebox", drawtype = "nodebox",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true, sunlight_propagates = true,
use_texture_alpha = true, use_texture_alpha = true,
walkable = false, walkable = false,
@ -120,7 +104,7 @@ minetest.register_node("mcl_portals:portal_end", {
node_box = { node_box = {
type = "fixed", type = "fixed",
fixed = { fixed = {
{-0.5, -0.5, -0.1, 0.5, 0.5, 0.1}, {-0.5, -0.5, -0.5, 0.5, 4/16, 0.5},
}, },
}, },
groups = {not_in_creative_inventory = 1}, groups = {not_in_creative_inventory = 1},
@ -130,84 +114,25 @@ minetest.register_node("mcl_portals:portal_end", {
_mcl_blast_resistance = 18000000, _mcl_blast_resistance = 18000000,
}) })
local function build_end_portal(pos, target3) local function build_end_portal_destination(pos)
local p = {x = pos.x - 1, y = pos.y - 1, z = pos.z} local p1 = {x = pos.x - 2, y = pos.y, z = pos.z-2}
local p1 = {x = pos.x - 1, y = pos.y - 1, z = pos.z} local p2 = {x = pos.x + 2, y = pos.y+2, z = pos.z+2}
local p2 = {x = p1.x + 3, y = p1.y + 4, z = p1.z}
for i = 1, 4 do
minetest.set_node(p, {name = fake_portal_frame})
p.y = p.y + 1
end
for i = 1, 3 do
minetest.set_node(p, {name = fake_portal_frame})
p.x = p.x + 1
end
for i = 1, 4 do
minetest.set_node(p, {name = fake_portal_frame})
p.y = p.y - 1
end
for i = 1, 3 do
minetest.set_node(p, {name = fake_portal_frame})
p.x = p.x - 1
end
for x = p1.x, p2.x do for x = p1.x, p2.x do
for y = p1.y, p2.y do for y = p1.y, p2.y do
p = {x = x, y = y, z = p1.z} for z = p1.z, p2.z do
if not (x == p1.x or x == p2.x or y == p1.y or y == p2.y) then local newp = {x=x,y=y,z=z}
minetest.set_node(p, {name = "mcl_portals:portal_end", param2 = 0}) -- Build obsidian platform
end if minetest.registered_nodes[minetest.get_node(newp).name].is_ground_content then
local meta = minetest.get_meta(p) if y == p1.y then
meta:set_string("portal_frame1", minetest.pos_to_string(p1)) minetest.set_node(newp, {name="mcl_core:obsidian"})
meta:set_string("portal_frame2", minetest.pos_to_string(p2)) else
meta:set_string("portal_target", minetest.pos_to_string(target3)) minetest.remove_node(newp)
for z = -2, 2 do
if z ~= 0 then
local newp = {x=p.x, y=p.y, z=p.z+z}
if y ~= p1.y then
if minetest.registered_nodes[
minetest.get_node(newp).name].is_ground_content then
minetest.remove_node(newp)
end
else
-- Build obsidian platform if floating
local newp_below = table.copy(newp)
newp_below.y = newp.y - 1
if minetest.get_node(newp).name == "air" and minetest.get_node(newp_below).name == "air" then
minetest.set_node(newp, {name="mcl_core:obsidian"})
end
end
end end
end end
end end
end end
end
local function find_end_target3_y2(target3_x, target3_z)
local start_y = math.random(SPAWN_MIN, SPAWN_MAX) -- Search start
if not nobj_cave then
nobj_cave = minetest.get_perlin(np_cave)
end end
local air = 0 -- Consecutive air nodes found
for y = start_y, SPAWN_MIN, -1 do
local nval_cave = nobj_cave:get3d({x = target3_x, y = y, z = target3_z})
if nval_cave > TCAVE then -- Cavern
air = air + 1
else -- Not cavern, check if 4 nodes of space above
if air >= 4 then
return y + 2
else -- Not enough space, reset air to zero
air = 0
end
end
end
return start_y -- Fallback
end end
local function move_check2(p1, max, dir) local function move_check2(p1, max, dir)
@ -304,18 +229,6 @@ local function make_end_portal(pos)
param2 = 1 param2 = 1
end end
local target3 = {x = p1.x, y = p1.y, z = p1.z}
target3.x = target3.x + 1
if target3.y < mcl_vars.mg_end_max and target3.y > mcl_vars.mg_end_min then
if mg_name == "flat" then
target3.y = mcl_vars.mg_bedrock_overworld_max + 5
else
target3.y = math.random(mcl_vars.mg_overworld_min + 40, mcl_vars.mg_overworld_min + 96)
end
else
target3.y = find_end_target3_y2(target3.x, target3.z)
end
for d = 0, 3 do for d = 0, 3 do
for y = p1.y, p2.y do for y = p1.y, p2.y do
local p = {} local p = {}
@ -345,67 +258,86 @@ minetest.register_abm({
label = "End portal teleportation", label = "End portal teleportation",
nodenames = {"mcl_portals:portal_end"}, nodenames = {"mcl_portals:portal_end"},
interval = 1, interval = 1,
chance = 2, chance = 1,
action = function(pos, node) action = function(pos, node)
for _,obj in ipairs(minetest.get_objects_inside_radius(pos,1)) do --maikerumine added for objects to travel -- Destroy legacy end portals created with quartz block frame
local lua_entity = obj:get_luaentity() --maikerumine added for objects to travel -- 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)
local legacy_portal_target = minetest.string_to_pos(meta:get_string("portal_target"))
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 if obj:is_player() or lua_entity then
-- No rapid back-and-forth teleportatio local _, dim = mcl_util.y_to_layer(pos.y)
if portal_cooloff[obj] then
return local target
end if dim == "end" then
local meta = minetest.get_meta(pos) -- End portal in the End:
local target3 = minetest.string_to_pos(meta:get_string("portal_target")) -- Teleport back to the player's spawn in the Overworld.
if target3 then -- TODO: Implement better spawn point detection
-- force emerge of target3 area
minetest.get_voxel_manip():read_from_map(target3, target3) target = minetest.string_to_pos(obj:get_attribute("mcl_beds:spawn"))
if not minetest.get_node_or_nil(target3) then if not target then
minetest.emerge_area( target = minetest.setting_get_pos("static_spawnpoint")
vector.subtract(target3, 4), vector.add(target3, 4)) end
if not target then
target = { x=0, y=0, z=0 }
end
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 end
-- teleport the object local objpos = obj:getpos()
minetest.after(3, function(obj, pos, target3) if objpos == nil then
-- No rapid back-and-forth teleportatio return
if portal_cooloff[obj] then end
return -- If player stands, player is at ca. something+0.5
end -- which might cause precision problems, so we used ceil.
local objpos = obj:getpos() objpos.y = math.ceil(objpos.y)
if objpos == nil then if minetest.get_node(objpos).name ~= "mcl_portals:portal_end" then
return return
end 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 -- Build destination
local function check_and_build_end_portal(pos, target3) local function check_and_build_end_portal_destination(pos)
local n = minetest.get_node_or_nil(target3) local n = minetest.get_node_or_nil(pos)
if n and n.name ~= "mcl_portals:portal_end" then if n and n.name ~= "mcl_core:obsidian" then
build_end_portal(target3, pos) build_end_portal_destination(pos)
minetest.after(2, check_and_build_end_portal, pos, target3) minetest.after(2, check_and_build_end_portal_destination, pos)
elseif not n then elseif not n then
minetest.after(1, check_and_build_end_portal, pos, target3) minetest.after(1, check_and_build_end_portal_destination, pos)
end end
end end
check_and_build_end_portal(pos, target3) local platform
check_and_build_end_portal_destination(platform_pos)
-- Teleport target = table.copy(platform_pos)
obj:setpos(target3) target.y = target.y + 1
minetest.sound_play("mcl_portals_teleport", {pos=target3, gain=0.5, max_hear_distance = 16})
-- Enable teleportation cooloff to prevent frequent back-and-forth teleportation
portal_cooloff[obj] = true
minetest.after(3, function(o)
portal_cooloff[o] = false
end, obj)
end, obj, pos, target3)
end end
-- Teleport
obj:set_pos(target)
-- Look towards the End island
if obj:is_player() and dim ~= "end" then
obj:set_look_horizontal(math.pi/2)
end
minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16})
end end
end end
end, end,
@ -414,20 +346,9 @@ minetest.register_abm({
--[[ ITEM OVERRIDES ]] --[[ ITEM OVERRIDES ]]
local portal_open_help = "To open an End portal, place an upright frame of quartz blocks with a length of 4 blocks and a height of 5 blocks, leaving only air in the center. After placing this frame, use an eye of ender on the frame. The eye of ender is destroyed in the process."
-- Fake frame material
minetest.override_item(fake_portal_frame, {
_doc_items_longdesc = "A block of quartz can be used to create End portals.",
_doc_items_usagehelp = portal_open_help,
on_destruct = destroy_portal,
})
-- End Portal Frame (TODO) -- End Portal Frame (TODO)
minetest.register_node("mcl_portals:end_portal_frame", { minetest.register_node("mcl_portals:end_portal_frame", {
description = "End Portal Frame", description = "End Portal Frame",
_doc_items_longdesc = "This block is currently only used for decoration. You can place an eye of ender into it for fun, but nothing will happen.",
groups = { creative_breakable = 1, deco_block = 1 }, groups = { creative_breakable = 1, deco_block = 1 },
tiles = { "mcl_portals_endframe_top.png", "mcl_portals_endframe_bottom.png", "mcl_portals_endframe_side.png" }, tiles = { "mcl_portals_endframe_top.png", "mcl_portals_endframe_bottom.png", "mcl_portals_endframe_side.png" },
paramtype2 = "facedir", paramtype2 = "facedir",
@ -477,7 +398,7 @@ end
-- Portal opener -- Portal opener
minetest.override_item("mcl_end:ender_eye", { minetest.override_item("mcl_end:ender_eye", {
_doc_items_longdesc = "An eye of ender can be used to open End portals.", _doc_items_longdesc = "An eye of ender can be used to open End portals.",
_doc_items_usagehelp = portal_open_help, -- TODO: _doc_items_usagehelp = ,
on_place = function(itemstack, user, pointed_thing) on_place = function(itemstack, user, pointed_thing)
-- Use pointed node's on_rightclick function first, if present -- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under) local node = minetest.get_node(pointed_thing.under)

View File

@ -45,6 +45,7 @@ local WITCH_HUT_HEIGHT = 3 -- Exact Y level to spawn witch huts at. This height
-- Content IDs -- Content IDs
local c_bedrock = minetest.get_content_id("mcl_core:bedrock") local c_bedrock = minetest.get_content_id("mcl_core:bedrock")
local c_obsidian = minetest.get_content_id("mcl_core:obsidian")
local c_stone = minetest.get_content_id("mcl_core:stone") local c_stone = minetest.get_content_id("mcl_core:stone")
local c_dirt = minetest.get_content_id("mcl_core:dirt") local c_dirt = minetest.get_content_id("mcl_core:dirt")
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass") local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
@ -1829,6 +1830,7 @@ minetest.register_on_generated(function(minp, maxp, seed)
-- End block fixes: -- End block fixes:
-- * Replace water with end stone or air (depending on height). -- * Replace water with end stone or air (depending on height).
-- * Remove stone, sand, dirt in v6 so our End map generator works in v6. -- * Remove stone, sand, dirt in v6 so our End map generator works in v6.
-- * Generate spawn platform (End portal destination)
elseif minp.y <= mcl_vars.mg_end_max and maxp.y >= mcl_vars.mg_end_min then elseif minp.y <= mcl_vars.mg_end_max and maxp.y >= mcl_vars.mg_end_min then
local nodes local nodes
if mg_name == "v6" then if mg_name == "v6" then
@ -1854,6 +1856,25 @@ minetest.register_on_generated(function(minp, maxp, seed)
end end
end end
-- Obsidian spawn platform
if minp.y <= mcl_vars.mg_end_platform_pos.y and maxp.y >= mcl_vars.mg_end_platform_pos.y and
minp.x <= mcl_vars.mg_end_platform_pos.x and maxp.x >= mcl_vars.mg_end_platform_pos.z and
minp.z <= mcl_vars.mg_end_platform_pos.z and maxp.z >= mcl_vars.mg_end_platform_pos.z then
for x=math.max(minp.x, mcl_vars.mg_end_platform_pos.x-2), math.min(maxp.x, mcl_vars.mg_end_platform_pos.x+2) do
for z=math.max(minp.z, mcl_vars.mg_end_platform_pos.z-2), math.min(maxp.z, mcl_vars.mg_end_platform_pos.z+2) do
for y=math.max(minp.y, mcl_vars.mg_end_platform_pos.y), math.min(maxp.y, mcl_vars.mg_end_platform_pos.y+2) do
local p_pos = area:index(x, y, z)
if y == mcl_vars.mg_end_platform_pos.y then
data[p_pos] = c_obsidian
else
data[p_pos] = c_air
end
end
end
end
lvm_used = true
end
end end
end end