diff --git a/README.md b/README.md index 754c8fd..6774071 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ SOFTWARE. ### [Attribution 3.0 Unported (CC BY 3.0)](https://creativecommons.org/licenses/by/3.0/) - * `nether_portal_ambient.ogg` & `nether_portal_ambient.0.ogg` are extractions from "Deep Cinematic Rumble Stereo" by [Patrick Lieberkind](http://www.lieberkindvisuals.dk) + * `nether_portal_ambient.ogg` & `nether_portal_ambient.0.ogg` are extractions from "Deep Cinematic Rumble Stereo" by [Patrick Lieberkind](http://www.lieberkindvisuals.dk), used under CC BY 3.0 * `nether_portal_extinguish.ogg` is an extraction from "Tight Laser Weapon Hit Scifi" by damjancd (https://freesound.org/people/damjancd), used under CC BY 3.0 * `nether_portal_ignite.ogg` is a derivative of "Flame Ignition" by hykenfreak (https://freesound.org/people/hykenfreak), used under CC BY 3.0. "Nether Portal ignite" is licensed under CC BY 3.0 by Treer. diff --git a/init.lua b/init.lua index 1f7b312..f8b2b8f 100644 --- a/init.lua +++ b/init.lua @@ -71,7 +71,7 @@ This opens to a truly hellish place, though for small mercies the air there is s The expedition parties have found no diamonds or gold, and after an experienced search party failed to return from the trail of a missing expedition party, I must conclude this is a dangerous place. ]], 10 * nether.FASTTRAVEL_FACTOR), - within_realm = function(pos) -- return true if pos is inside the Nether + is_within_realm = function(pos) -- return true if pos is inside the Nether return pos.y < nether.DEPTH end, diff --git a/portal_api.lua b/portal_api.lua index 30b2b69..fa4aad3 100644 --- a/portal_api.lua +++ b/portal_api.lua @@ -483,7 +483,7 @@ local function list_closest_portals(portal_definition, anchorPos, distance_limit local result = {} - local isRealm = portal_definition.within_realm(anchorPos) + local isRealm = portal_definition.is_within_realm(anchorPos) if distance_limit == nil then distance_limit = -1 end if y_factor == nil then y_factor = 1 end @@ -491,7 +491,7 @@ local function list_closest_portals(portal_definition, anchorPos, distance_limit local closingBrace = key:find(")", 6, true) if closingBrace ~= nil then local found_anchorPos = minetest.string_to_pos(key:sub(0, closingBrace)) - if found_anchorPos ~= nil and portal_definition.within_realm(found_anchorPos) == isRealm then + if found_anchorPos ~= nil and portal_definition.is_within_realm(found_anchorPos) == isRealm then local found_name = key:sub(closingBrace + 5) if found_name == portal_definition.name then local x = anchorPos.x - found_anchorPos.x @@ -915,7 +915,7 @@ local function ignite_portal(ignition_pos, ignition_node_name) 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 local destination_anchorPos, destination_orientation - if portal_definition.within_realm(ignition_pos) then + if portal_definition.is_within_realm(ignition_pos) then destination_anchorPos, destination_orientation = portal_definition.find_surface_anchorPos(anchorPos) else destination_anchorPos, destination_orientation = portal_definition.find_realm_anchorPos(anchorPos) @@ -1346,7 +1346,7 @@ function test_portaldef_is_valid(portal_definition) local result = test_shapedef_is_valid(portal_definition.shape) assert(portal_definition.wormhole_node_color >= 0 and portal_definition.wormhole_node_color < 8, "portaldef.wormhole_node_color must be between 0 and 7 (inclusive)") - assert(portal_definition.within_realm ~= nil, "portaldef.within_realm() must be implemented") + assert(portal_definition.is_within_realm ~= nil, "portaldef.is_within_realm() must be implemented") assert(portal_definition.find_realm_anchorPos ~= nil, "portaldef.find_realm_anchorPos() must be implemented") -- todo @@ -1442,7 +1442,8 @@ function nether.register_portal(name, portaldef) return false; end - portaldef.name = name + portaldef.name = name + portaldef.mod_name = minetest.get_current_modname() -- use portaldef_default for any values missing from portaldef or portaldef.sounds if portaldef.sounds ~= nil then setmetatable(portaldef.sounds, {__index = portaldef_default.sounds}) end @@ -1475,16 +1476,31 @@ function nether.register_portal(name, portaldef) end if test_portaldef_is_valid(portaldef) then - nether.registered_portals[portaldef.name] = portaldef - create_book_of_portals() - if not is_frame_node[portaldef.frame_node_name] then - register_frame_node(portaldef.frame_node_name) - is_frame_node[portaldef.frame_node_name] = true + -- check whether the portal definition clashes with anyone else's portal + local p1, p2 = portaldef.shape:get_p1_and_p2_from_anchorPos(vector.new(), 0) + local existing_portaldef = get_portal_definition(portaldef.frame_node_name, p1, p2) + if existing_portaldef ~= nil then + minetest.log("error", + portaldef.mod_name .." tried to register a portal '" .. portaldef.name .. "' made of " .. portaldef.frame_node_name .. + ", but it is the same material and shape as the portal '" .. existing_portaldef.name .. "' already registered by " .. existing_portaldef.mod_name .. + ". Edit the values one of those mods uses in its call to nether.register_portal() if you wish to resolve this clash.") + else + -- the new portaldef is good + nether.registered_portals[portaldef.name] = portaldef + create_book_of_portals() + + if not is_frame_node[portaldef.frame_node_name] then + -- add portal functions to the nodedef being used for the portal frame + register_frame_node(portaldef.frame_node_name) + is_frame_node[portaldef.frame_node_name] = true + end + + return true end - - return true end + + return false end function nether.unregister_portal(name) diff --git a/portal_api.txt b/portal_api.txt index 2806683..066e819 100644 --- a/portal_api.txt +++ b/portal_api.txt @@ -4,6 +4,20 @@ Portal API Reference The portal system used to get to the Nether can be used to create portals to other realms. +Pick a node type to have your portals built from, a shape in which the +portals must be built, and provide 3 functions for portals to find their +destination with: + * `find_realm_anchorPos(surface_anchorPos)` + * `find_surface_anchorPos(realm_anchorPos)` + * `is_within_realm(pos)` + +Optionally decorate by choosing portal colors, particles, media etc. + +See `init.lua` and `portal_examples.lua` for examples of 3 different portals. + +and perhaps a backup +node-type incase another mod is already using that node) + Portal code is more efficient when each type of portal uses a different type of node to build its frame out of, however it is possible to register more than one kind of portal with the same frame material — such as obsidian — provided @@ -44,6 +58,11 @@ Call these functions only at load time: * Returns true on success. Can return false if the portal definition clashes with a portal already registered by another mod, e.g. if the size and frame node is not unique. + A false return value should be handled, you could: + * Fall back to using a secondary material for portals to be built with. + * Use error() to exit lua with a message explaining how two mods are + clashing and how it can be resolved. + * Continue without a portal (the reason will be logged for the user). * `nether.unregister_portal(name)` * Unregisters the portal from the engine, and deletes the entry with key `name` from `nether.registered_portals` and associated internal tables. diff --git a/portal_examples.lua b/portal_examples.lua index 3a9deef..985fae6 100644 --- a/portal_examples.lua +++ b/portal_examples.lua @@ -52,7 +52,7 @@ Requiring 14 blocks of ice, but otherwise constructed the same as the portal to ]] .. "\u{25A9}"), - within_realm = function(pos) -- return true if pos is inside the Nether + is_within_realm = function(pos) -- return true if pos is inside the Nether return pos.y < nether.DEPTH end, @@ -114,7 +114,7 @@ nether.register_portal("stargate_portal", { ]] .. "\u{25A9}"), - within_realm = function(pos) -- return true if pos is inside the Nether + is_within_realm = function(pos) -- return true if pos is inside the Nether return pos.y < nether.DEPTH end,