Allow two or more portal types to be made with the same frame material

(provided they are different sized portals)
Removes direct references to the registered_portals table
This commit is contained in:
Treer 2019-07-04 21:44:30 +10:00 committed by SmallJoker
parent f38211e55d
commit 83c9ad574f

View File

@ -233,10 +233,9 @@ local TraditionalPortalShape = {
--=====================================================--
local registered_portals = {
-- todo: switch to lookup by name, ignite_portal can scan all registered portals
["default:obsidian"] = {
["netherportal"] = {
name = "netherportal",
shape = TraditionalPortalShape,
wormhole_node_name = "nether:portal",
wormhole_node_color = 0,
@ -293,6 +292,40 @@ local function get_orientation_from_param2(param2)
return param2 * 90
end
-- Combining frame_node_name, p1, and p2 will always be enough to uniquely identify a portal_defintion
-- WITHOUT needing to inspect the world. register_portal() will enforce this.
-- This function does not require the portal to be in a loaded chunk.
-- Returns nil if no portal_defintion matches the arguments
local function get_portal_defintion(frame_node_name, p1, p2)
local size = vector.add(vector.subtract(p2, p1), 1)
local rotated_size = {x = size.z, y = size.y, z = size.x}
for _, portal_def in pairs(registered_portals) do
if portal_def.frame_node_name == frame_node_name then
if vector.equals(size, portal_def.shape.size) or vector.equals(rotated_size, portal_def.shape.size) then
return portal_def
end
end
end
return nil
end
-- Returns a list of all portal_defintions with a frame made of frame_node_name.
-- Ideally no two portal types will be built from the same frame material so this call might be enough
-- to uniquely identify a portal_defintion without needing to inspect the world, HOWEVER we shouldn't
-- cramp anyone's style and prohibit non-nether use of obsidian to make portals, so it returns a list.
-- If the list contains more than one item then routines like ignite_portal() will have to search twice
-- for a portal and take twice the CPU.
local function list_portal_definitions_for_frame_node(frame_node_name)
local result = {}
for _, portal_def in pairs(registered_portals) do
if portal_def.frame_node_name == frame_node_name then table.insert(result, portal_def) end
end
return result
end
local extinguish_portal -- the function will be assigned to this further down, rather than having to define the function before other functions can use it.
local function set_portal_metadata(portal_definition, anchorPos, orientation, destination_wormholePos, ignite)
@ -508,7 +541,8 @@ local function volume_is_natural(minp, maxp)
local nodedef = minetest.registered_nodes[name]
if not nodedef.is_ground_content then
-- trees are natural but not "ground content"
if nodedef.groups == nil or (nodedef.groups.tree == nil and nodedef.groups.leaves == nil) then
local node_groups = nodedef.groups
if node_groups == nil or (node_groups.tree == nil and node_groups.leaves == nil) then
return false
end
end
@ -630,16 +664,16 @@ local function ignite_portal(ignition_pos)
local ignition_node_name = minetest.get_node(ignition_pos).name
-- find which sort of portals are made from the node that was clicked on
local portal_definition = registered_portals[ignition_node_name]
if portal_definition == nil then
return false -- no portals are made from the node at ignition_pos
end
local portal_definition_list = list_portal_definitions_for_frame_node(ignition_node_name)
for _, portal_definition in ipairs(portal_definition_list) do
local continue = false
-- check it was a portal frame that the player is trying to ignite
local anchorPos, orientation, is_ignited = is_portal_frame(portal_definition, ignition_pos)
if anchorPos == nil then
if DEBUG then minetest.chat_send_all("No portal frame found at " .. minetest.pos_to_string(ignition_pos)) end
return false -- no portal is here
if DEBUG then minetest.chat_send_all("No " .. portal_definition.name .. " portal frame found at " .. minetest.pos_to_string(ignition_pos)) end
continue = true -- no portal is here, but perhaps there more than one portal type we need to search for
elseif is_ignited then
if DEBUG then
local meta = minetest.get_meta(ignition_pos)
@ -647,6 +681,8 @@ local function ignite_portal(ignition_pos)
end
return false -- portal is already ignited
end
if continue == false then
if DEBUG then minetest.chat_send_all("Found portal frame. Looked at " .. minetest.pos_to_string(ignition_pos) .. ", found at " .. minetest.pos_to_string(anchorPos) .. " orientation " .. orientation) end
-- pick a destination
@ -664,6 +700,8 @@ local function ignite_portal(ignition_pos)
return true
end
end
end
-- WARNING - this is invoked by on_destruct, so you can't assume there's an accesible node at pos
@ -672,23 +710,22 @@ extinguish_portal = function(pos, node_name) -- assigned rather than declared be
-- mesecons seems to invoke action_off() 6 times every time you place a block?
if DEBUG then minetest.chat_send_all("extinguish_portal" .. minetest.pos_to_string(pos) .. " " .. node_name) end
-- find which sort of portals are made from the node that was clicked on
local portal_definition = registered_portals[node_name]
if portal_definition == nil then
minetest.log("error", "extinguish_portal() invoked on " .. node_name .. " but no registered portal is constructed from " .. node_name)
return false -- no portal frames are made from this type of node
end
local frame_node_name = portal_definition.frame_node_name
local wormhole_node_name = portal_definition.wormhole_node_name
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
if p1 == nil or p2 == nil then
return
end
local portal_definition = get_portal_defintion(node_name, p1, p2)
if portal_definition == nil then
minetest.log("error", "extinguish_portal() invoked on " .. node_name .. " but no registered portal is constructed from " .. node_name)
return -- no portal frames are made from this type of node
end
local frame_node_name = portal_definition.frame_node_name
local wormhole_node_name = portal_definition.wormhole_node_name
minetest.get_node_timer(get_timerPos_from_p1_and_p2(p1, p2)):stop()
for x = p1.x, p2.x do
@ -872,7 +909,7 @@ function run_wormhole(pos, time_elapsed)
if p1 ~= nil and p2 ~= nil then
-- look up the portal shape by what it's built from, so we know where the wormhole nodes will be located
if frame_node_name == nil then frame_node_name = minetest.get_node(pos).name end -- pos should be a frame node
portal_definition = registered_portals[frame_node_name]
portal_definition = get_portal_defintion(frame_node_name, p1, p2)
if portal_definition == nil then
minetest.log("error", "No portal with a \"" .. frame_node_name .. "\" frame is registered. run_wormhole" .. minetest.pos_to_string(pos) .. " was invoked but that location contains \"" .. frame_node_name .. "\"")
else