From 00cda53a138466c55b81ba44f6780f9993d9d0ed Mon Sep 17 00:00:00 2001 From: Treer Date: Wed, 6 Jan 2021 12:05:39 +1100 Subject: [PATCH 1/3] Add the Mantle Adds a magma oceans region to the nether outside the existing nether caverns, which can be reached via tunnels. Other misc changes: * chatcomment nether_whereami, a debug aid for knowing which perlin-noise region you are in * Nether ores no longer obtainable on the ceiling * Move crafts into crafts.lua * Add steam to lava cooling, and play bubbling lava upon death by lava * Add cracked netherbrick a decorative node which can only be obtained from dungeons or structures I encourage someone to improve or replace the cracked netherbrick texture. For copyright purposes it's currently a derivative work (by me, 2020) from nether_brick.png, which is licensed under CC BY-SA 3.0 by PilzAdam, so it can fall under the "All other media" PilzAdam's credit in readme.md rather than need its own entry. --- README.md | 7 +- crafts.lua | 64 +++ depends.txt | 10 +- init.lua | 16 + mapgen.lua | 260 ++++++++++-- mapgen_decorations.lua | 225 +++++++++- mapgen_mantle.lua | 476 ++++++++++++++++++++++ mapgen_nobiomes.lua | 9 +- nodes.lua | 396 ++++++++++++++++-- sounds/nether_lava_bubble.0.ogg | Bin 0 -> 7604 bytes sounds/nether_lava_bubble.ogg | Bin 0 -> 8085 bytes textures/nether_basalt.png | Bin 0 -> 678 bytes textures/nether_basalt_chiselled_side.png | Bin 0 -> 597 bytes textures/nether_basalt_chiselled_top.png | Bin 0 -> 594 bytes textures/nether_basalt_hewn.png | Bin 0 -> 1603 bytes textures/nether_basalt_side.png | Bin 0 -> 518 bytes textures/nether_brick_cracked.png | Bin 0 -> 290 bytes textures/nether_glowstone_deep.png | Bin 0 -> 666 bytes textures/nether_lava_crust_animated.png | Bin 0 -> 18533 bytes textures/nether_lava_source_animated.png | Bin 0 -> 2654 bytes textures/nether_particle_anim4.png | Bin 0 -> 288 bytes textures/nether_rack_deep.png | Bin 0 -> 353 bytes tools.lua | 19 + 23 files changed, 1388 insertions(+), 94 deletions(-) create mode 100644 crafts.lua create mode 100644 mapgen_mantle.lua create mode 100644 sounds/nether_lava_bubble.0.ogg create mode 100644 sounds/nether_lava_bubble.ogg create mode 100644 textures/nether_basalt.png create mode 100644 textures/nether_basalt_chiselled_side.png create mode 100644 textures/nether_basalt_chiselled_top.png create mode 100644 textures/nether_basalt_hewn.png create mode 100644 textures/nether_basalt_side.png create mode 100644 textures/nether_brick_cracked.png create mode 100644 textures/nether_glowstone_deep.png create mode 100644 textures/nether_lava_crust_animated.png create mode 100644 textures/nether_lava_source_animated.png create mode 100644 textures/nether_particle_anim4.png create mode 100644 textures/nether_rack_deep.png diff --git a/README.md b/README.md index 36d6b62..dca4ca7 100644 --- a/README.md +++ b/README.md @@ -36,17 +36,20 @@ SOFTWARE. * `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. ### [Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/) + * `nether_basalt`* (files starting with "nether_basalt"): Treer, 2020 * `nether_book_`* (files starting with "nether_book"): Treer, 2019-2020 * `nether_fumarole.ogg`: Treer, 2020 + * `nether_lava_bubble`* (files starting with "nether_lava_bubble"): Treer, 2020 + * `nether_lava_crust_animated.png`: Treer, 2019-2020 * `nether_particle_anim`* (files starting with "nether_particle_anim"): Treer, 2019 * `nether_portal_ignition_failure.ogg`: Treer, 2019 * `nether_smoke_puff.png`: Treer, 2020 ### [Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)](http://creativecommons.org/licenses/by-sa/3.0/) - * `nether_glowstone.png`: BlockMen + * `nether_glowstone`* (files starting with "nether_glowstone"): BlockMen * `nether_nether_ingot.png` & `nether_nether_lump.png`: color adjusted versions from "[default](https://github.com/minetest/minetest_game/tree/master/mods/default)" mod, originally by Gambit * `nether_portal.png`: [Extex101](https://github.com/Extex101), 2020 - * `nether_rack.png`: Zeg9 + * `nether_rack`* (files starting with "nether_rack"): Zeg9 * `nether_tool_`* (files starting with "nether_tool_"): color adjusted versions from "[default](https://github.com/minetest/minetest_game/tree/master/mods/default)" mod, originals by BlockMen All other media: Copyright © 2013 PilzAdam, licensed under CC BY-SA 3.0 by PilzAdam. \ No newline at end of file diff --git a/crafts.lua b/crafts.lua new file mode 100644 index 0000000..f880e19 --- /dev/null +++ b/crafts.lua @@ -0,0 +1,64 @@ +--[[ + + Copyright (C) 2013 PilzAdam + Copyright (C) 2020 lortas + Copyright (C) 2020 Treer + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + +]]-- + +minetest.register_craft({ + output = "nether:brick 4", + recipe = { + {"nether:rack", "nether:rack"}, + {"nether:rack", "nether:rack"}, + } +}) + +minetest.register_craft({ + output = "nether:fence_nether_brick 6", + recipe = { + {"nether:brick", "nether:brick", "nether:brick"}, + {"nether:brick", "nether:brick", "nether:brick"}, + }, +}) + +minetest.register_craft({ + output = "nether:brick_compressed", + recipe = { + {"nether:brick","nether:brick","nether:brick"}, + {"nether:brick","nether:brick","nether:brick"}, + {"nether:brick","nether:brick","nether:brick"}, + } +}) + +minetest.register_craft({ + output = "nether:basalt_hewn", + type = "shapeless", + recipe = { + "nether:basalt", + "nether:basalt", + }, +}) + +minetest.register_craft({ + output = "nether:basalt_chiselled 4", + recipe = { + {"nether:basalt_hewn", "nether:basalt_hewn"}, + {"nether:basalt_hewn", "nether:basalt_hewn"} + } +}) + +-- See tools.lua for tools related crafting \ No newline at end of file diff --git a/depends.txt b/depends.txt index a6ab237..00f426a 100644 --- a/depends.txt +++ b/depends.txt @@ -1,8 +1,8 @@ -stairs default -moreblocks? -mesecons? -loot? -dungeon_loot? +stairs doc_basics? +dungeon_loot? fire? +loot? +mesecons? +moreblocks? diff --git a/init.lua b/init.lua index c6e24c1..c09234e 100644 --- a/init.lua +++ b/init.lua @@ -116,6 +116,7 @@ end dofile(nether.path .. "/portal_api.lua") dofile(nether.path .. "/nodes.lua") dofile(nether.path .. "/tools.lua") +dofile(nether.path .. "/crafts.lua") if nether.NETHER_REALM_ENABLED then if nether.useBiomes then dofile(nether.path .. "/mapgen.lua") @@ -227,3 +228,18 @@ The expedition parties have found no diamonds or gold, and after an experienced }) end + + +-- Play bubbling lava sounds if player killed by lava +minetest.register_on_dieplayer( + function(player, reason) + if reason.node ~= nil and minetest.get_node_group(reason.node, "lava") > 0 or reason.node == "nether:lava_crust" then + minetest.sound_play( + "nether_lava_bubble", + -- this sample was encoded at 3x speed to reduce .ogg file size + -- at the expense of higher frequencies, so pitch it down ~3x + {to_player = player:get_player_name(), pitch = 0.3, gain = 0.8} + ) + end + end +) \ No newline at end of file diff --git a/mapgen.lua b/mapgen.lua index b449c5c..abc145a 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -2,6 +2,12 @@ Nether mod for minetest + "mapgen.lua" is the modern biomes-based Nether mapgen, which + requires Minetest v5.1 or greater + "mapgen_nobiomes.lua" is the legacy version of the mapgen, only used + in older versions of Minetest or in v6 worlds. + + Copyright (C) 2013 PilzAdam Permission to use, copy, modify, and/or distribute this software for @@ -27,10 +33,32 @@ local NETHER_FLOOR = nether.DEPTH_FLOOR local TCAVE = 0.6 local BLEND = 128 +-- parameters for central region +local REGION_BUFFER_THICKNESS = 0.2 +local CENTER_REGION_LIMIT = TCAVE - REGION_BUFFER_THICKNESS -- Netherrack gives way to Deep-Netherrack here +local CENTER_CAVERN_LIMIT = CENTER_REGION_LIMIT - 0.1 -- Deep-Netherrack gives way to air here +local SURFACE_CRUST_LIMIT = CENTER_CAVERN_LIMIT * 0.25 -- Crusted-lava at the surface of the lava ocean gives way to liquid lava here +local CRUST_LIMIT = CENTER_CAVERN_LIMIT * 0.85 -- Crusted-lava under the surface of the lava ocean gives way to liquid lava here +local BASALT_COLUMN_UPPER_LIMIT = CENTER_CAVERN_LIMIT * 0.9 -- Basalt columns may appear between these upper and lower limits +local BASALT_COLUMN_LOWER_LIMIT = CENTER_CAVERN_LIMIT * 0.25 -- This value is close to SURFACE_CRUST_LIMIT so basalt columns give way to "flowing" lava rivers --- Stuff -local math_max, math_min = math.max, math.min -- avoid needing table lookups each time a common math function is invoked +-- Shared Nether mapgen namespace +-- For mapgen files to share functions and constants +nether.mapgen = {} +local mapgen = nether.mapgen + +mapgen.TCAVE = TCAVE -- const needed in mapgen_mantle.lua +mapgen.BLEND = BLEND -- const needed in mapgen_mantle.lua +mapgen.CENTER_REGION_LIMIT = CENTER_REGION_LIMIT -- const needed in mapgen_mantle.lua +mapgen.CENTER_CAVERN_LIMIT = CENTER_CAVERN_LIMIT -- const needed in mapgen_mantle.lua +mapgen.BASALT_COLUMN_UPPER_LIMIT = BASALT_COLUMN_UPPER_LIMIT -- const needed in mapgen_mantle.lua +mapgen.BASALT_COLUMN_LOWER_LIMIT = BASALT_COLUMN_LOWER_LIMIT -- const needed in mapgen_mantle.lua + +mapgen.ore_ceiling = NETHER_CEILING - BLEND -- leave a solid 128 node cap of netherrack before introducing ores +mapgen.ore_floor = NETHER_FLOOR + BLEND + +local debugf = nether.debug if minetest.read_schematic == nil then -- Using biomes to create the Nether requires the ability for biomes to set "node_cave_liquid = air". @@ -41,6 +69,18 @@ if minetest.read_schematic == nil then error("This " .. nether.modname .. " mapgen requires Minetest v5.1 or greater, use mapgen_nobiomes.lua instead.", 0) end +-- Load helper functions for generating the mantle / center region +dofile(nether.path .. "/mapgen_mantle.lua") + + +-- Misc math functions + +-- avoid needing table lookups each time a common math function is invoked +local math_max, math_min, math_abs, math_floor = math.max, math.min, math.abs, math.floor + + +-- Inject nether_caverns biome + local function override_underground_biomes() -- https://forum.minetest.net/viewtopic.php?p=257522#p257522 -- Q: Is there a way to override an already-registered biome so I can get it out of the @@ -123,7 +163,7 @@ minetest.register_biome({ node_stone = "nether:native_mapgen", -- nether:native_mapgen is used here to prevent the native mapgen from placing ores and decorations. node_filler = "nether:native_mapgen", -- The lua on_generate will transform nether:rack_native into nether:rack then decorate and add ores. node_dungeon = "nether:brick", - --node_dungeon_alt = "default:mossycobble", + node_dungeon_alt = "nether:brick_cracked", node_dungeon_stair = "stairs:stair_nether_brick", -- Setting node_cave_liquid to "air" avoids the need to filter lava and water out of the mapchunk and -- surrounding shell (overdraw nodes beyond the mapchunk). @@ -152,19 +192,30 @@ minetest.register_ore({ clust_scarcity = 11 * 11 * 11, clust_num_ores = 3, clust_size = 2, - y_max = NETHER_CEILING, - y_min = NETHER_FLOOR, + y_max = mapgen.ore_ceiling, + y_min = mapgen.ore_floor +}) + +minetest.register_ore({ + ore_type = "scatter", + ore = "nether:lava_crust", -- crusted lava replaces of scattered glowstone in the mantle + wherein = "nether:rack_deep", + clust_scarcity = 16 * 16 * 16, + clust_num_ores = 4, + clust_size = 2, + y_max = mapgen.ore_ceiling, + y_min = mapgen.ore_floor }) minetest.register_ore({ ore_type = "scatter", ore = "default:lava_source", - wherein = "nether:rack", + wherein = {"nether:rack", "nether:rack_deep"}, clust_scarcity = 36 * 36 * 36, clust_num_ores = 4, clust_size = 2, - y_max = NETHER_CEILING, - y_min = NETHER_FLOOR, + y_max = mapgen.ore_ceiling, + y_min = mapgen.ore_floor }) minetest.register_ore({ @@ -173,8 +224,8 @@ minetest.register_ore({ wherein = "nether:rack", clust_scarcity = 14 * 14 * 14, clust_size = 8, - y_max = NETHER_CEILING, - y_min = NETHER_FLOOR + y_max = mapgen.ore_ceiling, + y_min = mapgen.ore_floor }) @@ -182,7 +233,7 @@ minetest.register_ore({ -- 3D noise -local np_cave = { +mapgen.np_cave = { offset = 0, scale = 1, spread = {x = 384, y = 128, z = 384}, -- squashed 3:1 @@ -199,23 +250,29 @@ local nobj_cave = nil local nbuf_cave = {} local dbuf = {} -local yblmin = NETHER_FLOOR + BLEND * 2 -local yblmax = NETHER_CEILING - BLEND * 2 -- Content ids local c_air = minetest.get_content_id("air") local c_netherrack = minetest.get_content_id("nether:rack") -local c_netherbrick = minetest.get_content_id("nether:brick") +local c_netherrack_deep = minetest.get_content_id("nether:rack_deep") +local c_dungeonbrick = minetest.get_content_id("nether:brick") +local c_dungeonbrick_alt = minetest.get_content_id("nether:brick_cracked") local c_netherbrick_slab = minetest.get_content_id("stairs:slab_nether_brick") local c_netherfence = minetest.get_content_id("nether:fence_nether_brick") local c_glowstone = minetest.get_content_id("nether:glowstone") local c_lava_source = minetest.get_content_id("default:lava_source") +local c_lavasea_source = minetest.get_content_id("nether:lava_source") -- same as lava but with staggered animation to look better as an ocean +local c_lava_crust = minetest.get_content_id("nether:lava_crust") local c_native_mapgen = minetest.get_content_id("nether:native_mapgen") -- Dungeon excavation functions +function is_dungeon_brick(node_id) + return node_id == c_dungeonbrick or node_id == c_dungeonbrick_alt +end + function build_dungeon_room_list(data, area) local result = {} @@ -310,6 +367,8 @@ end -- (Corridors and the parts of rooms which extend beyond the emerge boundary will remain filled) function excavate_dungeons(data, area, rooms) + local vi, node_id + -- any air from the native mapgen has been replaced by netherrack, but -- we don't want this inside dungeons, so fill dungeon rooms with air for _, roomInfo in ipairs(rooms) do @@ -319,9 +378,10 @@ function excavate_dungeons(data, area, rooms) for z = room_min.z, room_max.z do for y = room_min.y, room_max.y do - local vi = area:index(room_min.x, y, z) + vi = area:index(room_min.x, y, z) for x = room_min.x, room_max.x do - if data[vi] == c_netherrack then data[vi] = c_air end + node_id = data[vi] + if node_id == c_netherrack or node_id == c_netherrack_deep then data[vi] = c_air end vi = vi + 1 end end @@ -346,20 +406,22 @@ function decorate_dungeons(data, area, rooms) local window_y = roomInfo.y + math_min(2, room_max.y - roomInfo.y - 1) if room_seed % 3 == 0 and room_max.y < maxEdge.y then - -- Glowstone chandelier + -- Glowstone chandelier (feel free to replace with a fancy schematic) local vi = area:index(roomInfo.x, room_max.y + 1, roomInfo.z) - if data[vi] == c_netherbrick then data[vi] = c_glowstone end + if is_dungeon_brick(data[vi]) then data[vi] = c_glowstone end elseif room_seed % 4 == 0 and room_min.y > minEdge.y and room_min.x > minEdge.x and room_max.x < maxEdge.x and room_min.z > minEdge.z and room_max.z < maxEdge.z then -- lava well (feel free to replace with a fancy schematic) local vi = area:index(roomInfo.x, room_min.y, roomInfo.z) - if data[vi - yStride] == c_netherbrick then data[vi - yStride] = c_lava_source end - if data[vi - zStride] == c_air then data[vi - zStride] = c_netherbrick_slab end - if data[vi + zStride] == c_air then data[vi + zStride] = c_netherbrick_slab end - if data[vi - xStride] == c_air then data[vi - xStride] = c_netherbrick_slab end - if data[vi + xStride] == c_air then data[vi + xStride] = c_netherbrick_slab end + if is_dungeon_brick(data[vi - yStride]) then + data[vi - yStride] = c_lava_source + if data[vi - zStride] == c_air then data[vi - zStride] = c_netherbrick_slab end + if data[vi + zStride] == c_air then data[vi + zStride] = c_netherbrick_slab end + if data[vi - xStride] == c_air then data[vi - xStride] = c_netherbrick_slab end + if data[vi + xStride] == c_air then data[vi + xStride] = c_netherbrick_slab end + end end -- Barred windows @@ -377,15 +439,15 @@ function decorate_dungeons(data, area, rooms) local vi_max = area:index(room_max.x + 1, window_y, roomInfo.z) local locations = {-zStride, zStride, -zStride + yStride, zStride + yStride} for _, offset in ipairs(locations) do - if data[vi_min + offset] == c_netherbrick then data[vi_min + offset] = window_node end - if data[vi_max + offset] == c_netherbrick then data[vi_max + offset] = window_node end + if is_dungeon_brick(data[vi_min + offset]) then data[vi_min + offset] = window_node end + if is_dungeon_brick(data[vi_max + offset]) then data[vi_max + offset] = window_node end end vi_min = area:index(roomInfo.x, window_y, room_min.z - 1) vi_max = area:index(roomInfo.x, window_y, room_max.z + 1) locations = {-xStride, xStride, -xStride + yStride, xStride + yStride} for _, offset in ipairs(locations) do - if data[vi_min + offset] == c_netherbrick then data[vi_min + offset] = window_node end - if data[vi_max + offset] == c_netherbrick then data[vi_max + offset] = window_node end + if is_dungeon_brick(data[vi_min + offset]) then data[vi_min + offset] = window_node end + if is_dungeon_brick(data[vi_max + offset]) then data[vi_max + offset] = window_node end end end @@ -395,8 +457,43 @@ function decorate_dungeons(data, area, rooms) end +local yblmin = NETHER_FLOOR + BLEND * 2 +local yblmax = NETHER_CEILING - BLEND * 2 +-- At both the top and bottom of the Nether, as set by NETHER_CEILING and NETHER_FLOOR, +-- there is a 128 deep cap of solid netherrack, followed by a 128-deep blending zone +-- where Nether caverns may start to appear. +-- The solid zones and blending zones are achieved by adjusting the np_cave noise to be +-- outside the range where caverns form, this function returns that adjustment. +-- +-- Returns two values: the noise limit adjustment for nether caverns, and the +-- noise limit adjustment for the central region / mantle caverns +mapgen.get_mapgenblend_adjustments = function(y) + + -- floorAndCeilingBlend will normally be 0, but shifts toward 1 in the + -- blending zone, and goes higher than 1 in the solid zone between the + -- blending zone and the end of the nether. + local floorAndCeilingBlend = 0 + if y > yblmax then floorAndCeilingBlend = ((y - yblmax) / BLEND) ^ 2 end + if y < yblmin then floorAndCeilingBlend = ((yblmin - y) / BLEND) ^ 2 end + + -- the nether caverns exist when np_cave noise is greater than TCAVE, so + -- to fade out the nether caverns, adjust TCAVE upward. + local tcave_adj = floorAndCeilingBlend + + -- the central regions exists when np_cave noise is below CENTER_REGION_LIMIT, + -- so to fade out the mantle caverns adjust CENTER_REGION_LIMIT downward. + local centerRegionLimit_adj = -(CENTER_REGION_LIMIT * floorAndCeilingBlend) + + return tcave_adj, centerRegionLimit_adj +end + + + -- On-generated function +local tunnelCandidate_count = 0 +local tunnel_count = 0 +local total_chunk_count = 0 local function on_generated(minp, maxp, seed) if minp.y > NETHER_CEILING or maxp.y < NETHER_FLOOR then @@ -414,38 +511,120 @@ local function on_generated(minp, maxp, seed) local zCaveStride = yCaveStride * yCaveStride local chulens = {x = yCaveStride, y = yCaveStride, z = yCaveStride} - nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens) + nobj_cave = nobj_cave or minetest.get_perlin_map(mapgen.np_cave, chulens) local nvals_cave = nobj_cave:get_3d_map_flat(minp, nbuf_cave) - local dungeonRooms = build_dungeon_room_list(data, area) + local abs_cave_noise, abs_cave_noise_adjusted - for y = y0, y1 do -- Y loop first to minimise tcave calculations + local contains_nether = false + local contains_shell = false + local contains_mantle = false + local contains_ocean = false - local tcave = TCAVE - if y > yblmax then tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2 end - if y < yblmin then tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2 end + + for y = y0, y1 do -- Y loop first to minimise tcave & lava-sea calculations + + local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(y) + local above_lavasea = y > sea_level + local below_lavasea = y < sea_level + + local tcave_adj, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(y) + local tcave = TCAVE + tcave_adj + local tmantle = CENTER_REGION_LIMIT + centerRegionLimit_adj -- cavern_noise_adj already contains central_region_limit_adj, so tmantle is only for comparisons when cavern_noise_adj hasn't been added to the noise value + local cavern_noise_adj = + CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - + centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj so subtract centerRegionLimit_adj instead of adding for z = z0, z1 do local vi = area:index(x0, y, z) -- Initial voxelmanip index local ni = (z - z0) * zCaveStride + (y - y0) * yCaveStride + 1 + local noise2di = 1 + (z - z0) * yCaveStride for x = x0, x1 do - local id = data[vi] -- Existing node + local cave_noise = nvals_cave[ni] - if nvals_cave[ni] > tcave then + if cave_noise > tcave then + -- Prime region + -- This was the only region in initial versions of the Nether mod. + -- It is the only region that portals from the surface will open into. data[vi] = c_air - elseif id == c_air or id == c_native_mapgen then - data[vi] = c_netherrack -- excavate_dungeons() will mostly reverse this inside dungeons + contains_nether = true + + elseif -cave_noise > tcave then + -- Secondary/spare region + -- This secondary region is unused until someone decides to do something cool or novel with it. + -- Reaching here would require the player to first find and journey through the central region, + -- as it's always separated from the Prime region by the central region. + + data[vi] = c_netherrack -- For now I've just left this region as solid netherrack instead of air. + + -- Only set contains_nether to true here if you want tunnels created between the secondary region + -- and the central region. + --contains_nether = true + --data[vi] = c_air + else + -- netherrack walls and/or center region/mantle + abs_cave_noise = math_abs(cave_noise) + + -- abs_cave_noise_adjusted makes the center region smaller as distance from the lava ocean + -- increases, we do this by pretending the abs_cave_noise value is higher. + abs_cave_noise_adjusted = abs_cave_noise + cavern_noise_adj + + if abs_cave_noise_adjusted >= CENTER_CAVERN_LIMIT then + + local id = data[vi] -- Check existing node to avoid removing dungeons + if id == c_air or id == c_native_mapgen then + if abs_cave_noise < tmantle then + data[vi] = c_netherrack_deep + else + -- the shell seperating the mantle from the rest of the nether... + data[vi] = c_netherrack -- excavate_dungeons() will mostly reverse this inside dungeons + contains_shell = true + end + end + + elseif above_lavasea then + data[vi] = c_air + contains_mantle = true + elseif abs_cave_noise_adjusted < SURFACE_CRUST_LIMIT or (below_lavasea and abs_cave_noise_adjusted < CRUST_LIMIT) then + data[vi] = c_lavasea_source + contains_ocean = true + else + data[vi] = c_lava_crust + contains_ocean = true + end end ni = ni + 1 vi = vi + 1 + noise2di = noise2di + 1 end end end + if contains_mantle or contains_ocean then + mapgen.add_basalt_columns(data, area, minp, maxp) -- function provided by mapgen_mantle.lua + end + + if contains_nether and contains_mantle then + tunnelCandidate_count = tunnelCandidate_count + 1 + local success = mapgen.excavate_tunnel_to_center_of_the_nether(data, area, nvals_cave, minp, maxp) -- function provided by mapgen_mantle.lua + if success then tunnel_count = tunnel_count + 1 end + end + total_chunk_count = total_chunk_count + 1 + if total_chunk_count % 50 == 0 then + debugf( + "%s of %s chunks contain both nether and lava-sea (%s%%), %s chunks generated a pathway (%s%%)", + tunnelCandidate_count, + total_chunk_count, + math_floor(tunnelCandidate_count * 100 / total_chunk_count), + tunnel_count, + math_floor(tunnel_count * 100 / total_chunk_count) + ) + end + -- any air from the native mapgen has been replaced by netherrack, but we -- don't want netherrack inside dungeons, so fill known dungeon rooms with air. excavate_dungeons(data, area, dungeonRooms) @@ -453,10 +632,9 @@ local function on_generated(minp, maxp, seed) vm:set_data(data) - -- avoid generating decorations on the underside of the bottom of the nether - if minp.y > NETHER_FLOOR and maxp.y < NETHER_CEILING then minetest.generate_decorations(vm) end - minetest.generate_ores(vm) + minetest.generate_decorations(vm) + vm:set_lighting({day = 0, night = 0}, minp, maxp) vm:calc_lighting() vm:update_liquids() @@ -467,7 +645,7 @@ end -- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal. -- player_name is optional, allowing a player to spawn a remote portal in their own protected areas. function nether.find_nether_ground_y(target_x, target_z, start_y, player_name) - local nobj_cave_point = minetest.get_perlin(np_cave) + local nobj_cave_point = minetest.get_perlin(mapgen.np_cave) local air = 0 -- Consecutive air nodes found local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, "nether_portal") diff --git a/mapgen_decorations.lua b/mapgen_decorations.lua index 7005da4..5ceb5a6 100644 --- a/mapgen_decorations.lua +++ b/mapgen_decorations.lua @@ -25,10 +25,16 @@ -- emerged or not before the decoration was placed. local allow_lava_decorations = nether.useBiomes +-- Keep compatibility with mapgen_nobiomes.lua, so hardcoding 128 +-- instead of using nether.mapgen.BLEND +local decoration_ceiling = nether.DEPTH_CEILING - 128 +local decoration_floor = nether.DEPTH_FLOOR + 128 + local _ = {name = "air", prob = 0} local A = {name = "air", prob = 255, force_place = true} local G = {name = "nether:glowstone", prob = 255, force_place = true} local N = {name = "nether:rack", prob = 255} +local D = {name = "nether:rack_deep", prob = 255} local S = {name = "nether:sand", prob = 255, force_place = true} local L = {name = "default:lava_source", prob = 255, force_place = true} local F = {name = "nether:fumarole", prob = 255, force_place = true} @@ -125,8 +131,8 @@ minetest.register_decoration({ sidelen = 80, fill_ratio = 0.0003, biomes = {"nether_caverns"}, - y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = schematic_GlowstoneStalactite, flags = "place_center_x,place_center_z,force_placement,all_ceilings", place_offset_y=-3 @@ -139,8 +145,8 @@ minetest.register_decoration({ sidelen = 80, fill_ratio = 0.0008, biomes = {"nether_caverns"}, - y_max = nether.DEPTH_CEILING, -- keep compatibility with mapgen_nobiomes.lua - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = schematic_GlowstoneStalactite, replacements = {["nether:glowstone"] = "nether:rack"}, flags = "place_center_x,place_center_z,all_ceilings", @@ -148,6 +154,193 @@ minetest.register_decoration({ }) +local schematic_GreaterStalactite = { + size = {x = 3, y = 23, z = 3}, + data = { -- note that data is upside down + + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, D, _, + _, D, _, + _, D, _, + _, D, _, + D, D, D, + D, D, D, + D, D, D, + _, D, _, + _, _, _, + _, _, _, + + _, D, _, -- ypos 0, prob 85% (218/255) + _, D, _, -- ypos 1, prob 85% (218/255) + _, D, _, -- ypos 2, prob 85% (218/255) + _, D, _, -- ypos 3, prob 85% (218/255) + _, D, _, -- ypos 4, prob 85% (218/255) + _, D, _, -- ypos 5, prob 85% (218/255) + _, D, _, -- ypos 6, prob 85% (218/255) + _, D, _, -- ypos 7, prob 85% (218/255) + _, D, _, -- ypos 8, prob 85% (218/255) + _, D, D, -- ypos 9, prob 50% (128/256) to make half of stalactites asymmetric + _, D, D, -- ypos 10, prob 50% (128/256) to make half of stalactites asymmetric + _, D, D, -- ypos 11, prob 50% (128/256) to make half of stalactites asymmetric + _, D, D, -- ypos 12, prob 50% (128/256) to make half of stalactites asymmetric + D, D, D, -- ypos 13, prob 75% (192/256) + D, D, D, -- ypos 14, prob 75% (192/256) + D, D, D, -- ypos 15, prob 100% + D, D, D, -- ypos 16, prob 100% + D, D, D, -- ypos 17, prob 100% + D, D, D, -- ypos 18, prob 100% + D, D, D, -- ypos 19, prob 75% (192/256) + D, D, D, -- ypos 20, prob 85% (218/255) + _, D, D, -- ypos 21, prob 50% (128/256) to make half of stalactites asymmetric + _, D, _, -- ypos 22, prob 100% + + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, _, _, + _, D, _, + _, D, _, + _, D, _, + _, D, _, + _, D, _, + D, D, D, + D, D, D, + D, D, D, + _, D, _, + _, D, _, + _, _, _, + + }, + -- Y-slice probabilities do not function correctly for ceiling schematic + -- decorations because they are inverted, so ypos numbers have been inverted + -- to match, and a larger offset in place_offset_y should be used (e.g. -3). + yslice_prob = { + {ypos = 21, prob = 128}, + {ypos = 20, prob = 218}, + {ypos = 19, prob = 192}, + {ypos = 14, prob = 192}, + {ypos = 13, prob = 192}, + {ypos = 12, prob = 128}, + {ypos = 11, prob = 128}, + {ypos = 10, prob = 128}, + {ypos = 9, prob = 128}, + {ypos = 8, prob = 218}, + {ypos = 7, prob = 218}, + {ypos = 6, prob = 218}, + {ypos = 5, prob = 218}, + {ypos = 4, prob = 218}, + {ypos = 3, prob = 218}, + {ypos = 2, prob = 218}, + {ypos = 1, prob = 218}, + {ypos = 0, prob = 218} + } +} + + + +-- A stalagmite is an upsidedown stalactite, so +-- use the GreaterStalactite to create a ToweringStalagmite schematic +local schematic_ToweringStalagmite = { + size = schematic_GreaterStalactite.size, + data = {}, + yslice_prob = {} +} +local array_length = #schematic_GreaterStalactite.data + 1 +for i, node in ipairs(schematic_GreaterStalactite.data) do + schematic_ToweringStalagmite.data[array_length - i] = node +end +y_size = schematic_GreaterStalactite.size.y +for i, node in ipairs(schematic_GreaterStalactite.yslice_prob) do + schematic_ToweringStalagmite.yslice_prob[i] = { + -- we can safely lower the prob. to gain more variance because floor based schematics + -- don't have the bug where missing lines moves them away from the surface + prob = schematic_GreaterStalactite.yslice_prob[i].prob - 20, + ypos = y_size - 1 - schematic_GreaterStalactite.yslice_prob[i].ypos + } +end + +minetest.register_decoration({ + name = "Deep-glowstone stalactite", + deco_type = "schematic", + place_on = "nether:rack_deep", + sidelen = 80, + fill_ratio = 0.0003, + biomes = {"nether_caverns"}, + y_max = decoration_ceiling, + y_min = decoration_floor, + schematic = schematic_GlowstoneStalactite, + replacements = {["nether:rack"] = "nether:rack_deep", ["nether:glowstone"] = "nether:glowstone_deep"}, + flags = "place_center_x,place_center_z,force_placement,all_ceilings", + place_offset_y=-3 +}) + +minetest.register_decoration({ + name = "Deep-glowstone stalactite outgrowth", + deco_type = "schematic", + place_on = "nether:glowstone_deep", + sidelen = 40, + fill_ratio = 0.15, + biomes = {"nether_caverns"}, + y_max = decoration_ceiling, + y_min = decoration_floor, + schematic = { + size = {x = 1, y = 4, z = 1}, + data = { G, G, G, G } + }, + replacements = {["nether:glowstone"] = "nether:glowstone_deep"}, + flags = "place_center_x,place_center_z,all_ceilings", +}) + +minetest.register_decoration({ + name = "Deep-netherrack stalactite", + deco_type = "schematic", + place_on = "nether:rack_deep", + sidelen = 80, + fill_ratio = 0.0003, + biomes = {"nether_caverns"}, + y_max = decoration_ceiling, + y_min = decoration_floor, + schematic = schematic_GlowstoneStalactite, + replacements = {["nether:rack"] = "nether:rack_deep", ["nether:glowstone"] = "nether:rack_deep"}, + flags = "place_center_x,place_center_z,force_placement,all_ceilings", + place_offset_y=-3 +}) + +minetest.register_decoration({ + name = "Deep-netherrack towering stalagmite", + deco_type = "schematic", + place_on = "nether:rack_deep", + sidelen = 80, + fill_ratio = 0.001, + biomes = {"nether_caverns"}, + y_max = decoration_ceiling, + y_min = decoration_floor, + schematic = schematic_ToweringStalagmite, + replacements = {["nether:basalt"] = "nether:rack_deep"}, + flags = "place_center_x,place_center_z,force_placement,all_floors", + place_offset_y=-2 +}) + -- ======================================= -- Concealed crevice / Lava sinkhole -- ======================================= @@ -161,8 +354,8 @@ if allow_lava_decorations then sidelen = 80, fill_ratio = 0.002, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, -- keep compatibility with mapgen_nobiomes.lua - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = { size = {x = 4, y = 7, z = 4}, data = { -- note that data is upside down @@ -263,8 +456,8 @@ minetest.register_decoration({ sidelen = 80, fill_ratio = 0.005, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = schematic_fumarole, replacements = replacements_full, flags = "place_center_x,place_center_z,all_floors", @@ -292,8 +485,8 @@ minetest.register_decoration({ sidelen = 8, noise_params = fumarole_clump_noise, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = schematic_fumarole, replacements = replacements_full, flags = "place_center_x,place_center_z,all_floors", @@ -308,8 +501,8 @@ minetest.register_decoration({ sidelen = 8, noise_params = fumarole_clump_noise, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = schematic_fumarole, replacements = replacements_slab, flags = "place_center_x,place_center_z,all_floors", @@ -324,8 +517,8 @@ minetest.register_decoration({ sidelen = 8, noise_params = fumarole_clump_noise, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = { size = {x = 4, y = 4, z = 4}, data = { -- note that data is upside down @@ -363,8 +556,8 @@ minetest.register_decoration({ sidelen = 8, noise_params = fumarole_clump_noise, biomes = {"nether_caverns"}, - y_max = nether.DEPTH, - y_min = nether.DEPTH_FLOOR, + y_max = decoration_ceiling, + y_min = decoration_floor, schematic = { size = {x = 4, y = 5, z = 4}, data = { -- note that data is upside down diff --git a/mapgen_mantle.lua b/mapgen_mantle.lua new file mode 100644 index 0000000..0add888 --- /dev/null +++ b/mapgen_mantle.lua @@ -0,0 +1,476 @@ +--[[ + + Nether mod for minetest + + This file contains helper functions for generating the Mantle + (AKA center region), which are moved into a separate file to keep the + size of mapgen.lua manageable. + + + Copyright (C) 2021 Treer + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + +]]-- + + +local debugf = nether.debug +local mapgen = nether.mapgen + +local BASALT_COLUMN_UPPER_LIMIT = mapgen.BASALT_COLUMN_UPPER_LIMIT +local BASALT_COLUMN_LOWER_LIMIT = mapgen.BASALT_COLUMN_LOWER_LIMIT + + +-- 2D noise for basalt formations +local np_basalt = { + offset =-0.85, + scale = 1, + spread = {x = 46, y = 46, z = 46}, + seed = 1000, + octaves = 5, + persistence = 0.5, + lacunarity = 2.6, + flags = "eased" +} + + +-- Buffers and objects we shouldn't recreate every on_generate + +local nobj_basalt = nil +local nbuf_basalt = {} +local cavePerlin = nil + +-- Content ids + +local c_air = minetest.get_content_id("air") +local c_netherrack_deep = minetest.get_content_id("nether:rack_deep") +local c_glowstone = minetest.get_content_id("nether:glowstone") +local c_lavasea_source = minetest.get_content_id("nether:lava_source") -- same as lava but with staggered animation to look better as an ocean +local c_lava_crust = minetest.get_content_id("nether:lava_crust") +local c_basalt = minetest.get_content_id("nether:basalt") + + +-- Math funcs +local math_max, math_min, math_abs, math_floor = math.max, math.min, math.abs, math.floor -- avoid needing table lookups each time a common math function is invoked + +function random_unit_vector() + return vector.normalize({ + x = math.random() - 0.5, + y = math.random() - 0.5, + z = math.random() - 0.5 + }) +end + +-- returns the smallest component in the vector +function vector_min(v) + return math_min(v.x, math_min(v.y, v.z)) +end + + +-- Mantle mapgen functions (AKA Center region) + +-- Returns (absolute height, fractional distance from ceiling or sea floor) +-- the fractional distance from ceiling or sea floor is a value between 0 and 1 (inclusive) +-- Note it may find the most relevent sea-level - not necesssarily the one you are closest +-- to, since the space above the sea reaches much higher than the depth below the sea. +mapgen.find_nearest_lava_sealevel = function(y) + -- todo: put oceans near the bottom of chunks to improve ability to generate tunnels to the center + -- todo: constrain y to be not near the bounds of the nether + -- todo: add some random adj at each level, seeded only by the level height + local sealevel = math.floor((y + 100) / 200) * 200 + --local sealevel = math.floor((y + 80) / 160) * 160 + --local sealevel = math.floor((y + 120) / 240) * 240 + + local cavern_limits_fraction + local height_above_sea = y - sealevel + if height_above_sea >= 0 then + cavern_limits_fraction = math_min(1, height_above_sea / 95) + else + -- approaches 1 much faster as the lava sea is shallower than the cavern above it + cavern_limits_fraction = math_min(1, -height_above_sea / 40) + end + + return sealevel, cavern_limits_fraction +end + + + + +mapgen.add_basalt_columns = function(data, area, minp, maxp) + -- Basalt columns are structures found in lava oceans, and the only way to obtain + -- nether basalt. + -- Their x, z position is determined by a 2d noise map and a 2d slice of the cave + -- noise (taken at lava-sealevel). + + local x0, y0, z0 = minp.x, math_max(minp.y, nether.DEPTH_FLOOR), minp.z + local x1, y1, z1 = maxp.x, math_min(maxp.y, nether.DEPTH_CEILING), maxp.z + + local yStride = area.ystride + local yCaveStride = x1 - x0 + 1 + + cavePerlin = cavePerlin or minetest.get_perlin(mapgen.np_cave) + nobj_basalt = nobj_basalt or minetest.get_perlin_map(np_basalt, {x = yCaveStride, y = yCaveStride}) + local nvals_basalt = nobj_basalt:get_2d_map_flat({x=minp.x, y=minp.z}, {x=yCaveStride, y=yCaveStride}, nbuf_basalt) + + local nearest_sea_level, _ = mapgen.find_nearest_lava_sealevel(math_floor((y0 + y1) / 2)) + + local leeway = mapgen.CENTER_CAVERN_LIMIT * 0.18 + + for z = z0, z1 do + local noise2di = 1 + (z - z0) * yCaveStride + + for x = x0, x1 do + + local basaltNoise = nvals_basalt[noise2di] + if basaltNoise > 0 then + -- a basalt column is here + + local abs_sealevel_cave_noise = math_abs(cavePerlin:get3d({x = x, y = nearest_sea_level, z = z})) + + -- Add Some quick deterministic noise to the column heights + -- This is probably not good noise, but it doesn't have to be. + local fastNoise = 17 + fastNoise = 37 * fastNoise + y0 + fastNoise = 37 * fastNoise + z + fastNoise = 37 * fastNoise + x + fastNoise = 37 * fastNoise + math_floor(basaltNoise * 32) + + local columnHeight = basaltNoise * 18 + ((fastNoise % 3) - 1) + + -- columns should drop below sealevel where lava rivers are flowing + -- i.e. anywhere abs_sealevel_cave_noise < BASALT_COLUMN_LOWER_LIMIT + -- And we'll also have it drop off near the edges of the lava ocean so that + -- basalt columns can only be found by the player reaching a lava ocean. + local lowerClip = (math_min(math_max(abs_sealevel_cave_noise, BASALT_COLUMN_LOWER_LIMIT - leeway), BASALT_COLUMN_LOWER_LIMIT + leeway) - BASALT_COLUMN_LOWER_LIMIT) / leeway + local upperClip = (math_min(math_max(abs_sealevel_cave_noise, BASALT_COLUMN_UPPER_LIMIT - leeway), BASALT_COLUMN_UPPER_LIMIT + leeway) - BASALT_COLUMN_UPPER_LIMIT) / leeway + local columnHeightAdj = lowerClip * -upperClip -- all are values between 1 and -1 + + columnHeight = columnHeight + math_floor(columnHeightAdj * 12 - 12) + + local vi = area:index(x, y0, z) -- Initial voxelmanip index + + for y = y0, y1 do -- Y loop first to minimise tcave & lava-sea calculations + + if y < nearest_sea_level + columnHeight then + + local id = data[vi] -- Existing node + if id == c_lava_crust or id == c_lavasea_source or (id == c_air and y > nearest_sea_level) then + -- Avoid letting columns extend beyond the central region. + -- (checking node ids saves having to calculate abs_cave_noise_adjusted here + -- to test it against CENTER_CAVERN_LIMIT) + data[vi] = c_basalt + end + end + + vi = vi + yStride + end + end + + noise2di = noise2di + 1 + end + end +end + + +-- returns an array of points from pos1 and pos2 which deviate from a straight line +-- but which don't venture too close to a chunk boundary +function generate_waypoints(pos1, pos2, minp, maxp) + + local segSize = 10 + local maxDeviation = 7 + local minDistanceFromChunkWall = 5 + + local pathVec = vector.subtract(pos2, pos1) + local pathVecNorm = vector.normalize(pathVec) + local pathLength = vector.distance(pos1, pos2) + local minBound = vector.add(minp, minDistanceFromChunkWall) + local maxBound = vector.subtract(maxp, minDistanceFromChunkWall) + + local result = {} + result[1] = pos1 + + local segmentCount = math_floor(pathLength / segSize) + for i = 1, segmentCount do + local waypoint = vector.add(pos1, vector.multiply(pathVec, i / (segmentCount + 1))) + + -- shift waypoint a few blocks in a random direction orthogonally to the pathVec, to make the path crooked. + local crossProduct + repeat + crossProduct = vector.normalize(vector.cross(pathVecNorm, random_unit_vector())) + until vector.length(crossProduct) > 0 + local deviation = vector.multiply(crossProduct, math.random(1, maxDeviation)) + waypoint = vector.add(waypoint, deviation) + waypoint = { + x = math_min(maxBound.x, math_max(minBound.x, waypoint.x)), + y = math_min(maxBound.y, math_max(minBound.y, waypoint.y)), + z = math_min(maxBound.z, math_max(minBound.z, waypoint.z)) + } + + result[#result + 1] = waypoint + end + + result[#result + 1] = pos2 + return result +end + + +function excavate_pathway(data, area, nether_pos, center_pos, minp, maxp) + + local ystride = area.ystride + local zstride = area.zstride + + math.randomseed(nether_pos.x + 10 * nether_pos.y + 100 * nether_pos.z) -- so each tunnel generates deterministically (this doesn't have to be a quality seed) + local dist = math_floor(vector.distance(nether_pos, center_pos)) + local waypoints = generate_waypoints(nether_pos, center_pos, minp, maxp) + + -- First pass: record path details + local linedata = {} + local last_pos = {} + local line_index = 1 + local first_filled_index, boundary_index, last_filled_index + for i = 0, dist do + -- Bresenham's line would be good here, but too much lua code + local waypointProgress = (#waypoints - 1) * i / dist + local segmentIndex = math_min(math_floor(waypointProgress) + 1, #waypoints - 1) -- from the integer portion of waypointProgress + local segmentInterp = waypointProgress - (segmentIndex - 1) -- the remaining fractional portion + local segmentStart = waypoints[segmentIndex] + local segmentVector = vector.subtract(waypoints[segmentIndex + 1], segmentStart) + local pos = vector.round(vector.add(segmentStart, vector.multiply(segmentVector, segmentInterp))) + + if not vector.equals(pos, last_pos) then + local vi = area:indexp(pos) + local node_id = data[vi] + linedata[line_index] = { + pos = pos, + vi = vi, + node_id = node_id + } + if boundary_index == nil and node_id == c_netherrack_deep then + boundary_index = line_index + end + if node_id == c_air then + if boundary_index ~= nil and last_filled_index == nil then + last_filled_index = line_index + end + else + if first_filled_index == nil then + first_filled_index = line_index + end + end + line_index = line_index + 1 + last_pos = pos + end + end + first_filled_index = first_filled_index or 1 + last_filled_index = last_filled_index or #linedata + boundary_index = boundary_index or last_filled_index + + + -- limit tunnel radius to roughly the closest that startPos or stopPos comes to minp-maxp, so we + -- don't end up exceeding minp-maxp and having excavation filled in when the next chunk is generated. + local startPos, stopPos = linedata[first_filled_index].pos, linedata[last_filled_index].pos + local radiusLimit = vector_min(vector.subtract(startPos, minp)) + radiusLimit = math_min(radiusLimit, vector_min(vector.subtract(stopPos, minp))) + radiusLimit = math_min(radiusLimit, vector_min(vector.subtract(maxp, startPos))) + radiusLimit = math_min(radiusLimit, vector_min(vector.subtract(maxp, stopPos))) + + if radiusLimit < 4 then -- This is a logic check, ignore it. It could be commented out + -- 4 is (79 - 75), and shouldn't be possible if sampling-skip was 10 + -- i.e. if sampling-skip was 10 then {5, 15, 25, 35, 45, 55, 65, 75} should be sampled from possible positions 0 to 79 + debugf("Error: radiusLimit %s is smaller then half the sampling distance. min %s, max %s, start %s, stop %s", radiusLimit, minp, maxp, startPos, stopPos) + end + radiusLimit = radiusLimit + 1 -- chunk walls wont be visibly flat if the radius only exceeds it a little ;) + + -- Second pass: excavate + local start_index, stop_index = math_max(1, first_filled_index - 2), math_min(#linedata, last_filled_index + 3) + for i = start_index, stop_index, 3 do + + -- Adjust radius so that tunnels start wide but thin out in the middle + local distFromEnds = 1 - math_abs(((start_index + stop_index) / 2) - i) / ((stop_index - start_index) / 2) -- from 0 to 1, with 0 at ends and 1 in the middle + -- Have it more flaired at the ends, rather than linear. + -- i.e. sizeAdj approaches 1 quickly as distFromEnds increases + local distFromMiddle = 1 - distFromEnds + local sizeAdj = 1 - (distFromMiddle * distFromMiddle * distFromMiddle) + + local radius = math_min(radiusLimit, math.random(50 - (25 * sizeAdj), 80 - (45 * sizeAdj)) / 10) + local radiusCubed = radius * radius + local radiusCeil = math_floor(radius + 0.5) + + linedata[i].radius = radius -- Needed in third pass + linedata[i].distFromEnds = distFromEnds -- Needed in third pass + + local vi = linedata[i].vi + for z = -radiusCeil, radiusCeil do + local vi_z = vi + z * zstride + for y = -radiusCeil, radiusCeil do + local vi_zy = vi_z + y * ystride + local xSquaredLimit = radiusCubed - (z * z + y * y) + for x = -radiusCeil, radiusCeil do + if x * x < xSquaredLimit then + data[vi_zy + x] = c_air + end + end + end + end + + end + + -- Third pass: decorate + -- Add glowstones to make tunnels to the mantle easyier to find + -- https://i.imgur.com/sRA28x7.jpg + for i = start_index, stop_index, 3 do + if linedata[i].distFromEnds < 0.3 then + local glowcount = 0 + local radius = linedata[i].radius + for _ = 1, 20 do + local testPos = vector.round(vector.add(linedata[i].pos, vector.multiply(random_unit_vector(), radius + 0.5))) + local vi = area:indexp(testPos) + if data[vi] ~= c_air then + data[vi] = c_glowstone + glowcount = glowcount + 1 + --else + -- data[vi] = c_debug + end + if glowcount >= 2 then break end + end + end + end + +end + + +-- excavates a tunnel connecting the Primary or Secondary region with the mantle / central region +-- if a suitable path is found. +-- Returns true if successful +mapgen.excavate_tunnel_to_center_of_the_nether = function(data, area, nvals_cave, minp, maxp) + + local result = false + local extent = vector.subtract(maxp, minp) + local skip = 10 -- sampling rate of 1 in 10 + + local highest = -1000 + local lowest = 1000 + local lowest_vi + local highest_vi + + local yCaveStride = maxp.x - minp.x + 1 + local zCaveStride = yCaveStride * yCaveStride + + local vi_offset = area:indexp(vector.add(minp, math_floor(skip / 2))) -- start half the sampling distance away from minp + local vi, ni + + for y = 0, extent.y - 1, skip do + local sealevel = mapgen.find_nearest_lava_sealevel(minp.y + y) + + if minp.y + y > sealevel then -- only create tunnels above sea level + for z = 0, extent.z - 1, skip do + + vi = vi_offset + y * area.ystride + z * area.zstride + ni = z * zCaveStride + y * yCaveStride + 1 + for x = 0, extent.x - 1, skip do + + local noise = math_abs(nvals_cave[ni]) + if noise < lowest then + lowest = noise + lowest_vi = vi + end + if noise > highest then + highest = noise + highest_vi = vi + end + ni = ni + skip + vi = vi + skip + end + end + end + end + + if lowest < mapgen.CENTER_CAVERN_LIMIT and highest > mapgen.TCAVE + 0.03 then + + local mantle_y = area:position(lowest_vi).y + local sealevel, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(mantle_y) + local _, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(mantle_y) + local cavern_noise_adj = + mapgen.CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - + centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj instead of adding + + if lowest + cavern_noise_adj < mapgen.CENTER_CAVERN_LIMIT then + excavate_pathway(data, area, area:position(highest_vi), area:position(lowest_vi), minp, maxp) + result = true + end + end + return result +end + + +minetest.register_chatcommand("nether_whereami", + { + description = "Describes which region of the nether the player is in", + privs = {debug = true}, + func = function(name, param) + + local player = minetest.get_player_by_name(name) + if player == nil then return false, "Unknown player position" end + + local pos = vector.round(player:get_pos()) + if pos.y > nether.DEPTH_CEILING or pos.y < nether.DEPTH_FLOOR then + return true, "The Overworld" + end + + cavePerlin = cavePerlin or minetest.get_perlin(mapgen.np_cave) + local densityNoise = cavePerlin:get_3d(pos) + local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(pos.y) + local tcave_adj, centerRegionLimit_adj = mapgen.get_mapgenblend_adjustments(pos.y) + local tcave = mapgen.TCAVE + tcave_adj + local tmantle = mapgen.CENTER_REGION_LIMIT + centerRegionLimit_adj + local cavern_noise_adj = + mapgen.CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - + centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj so subtract centerRegionLimit_adj instead of adding + + local desc + + if densityNoise > tcave then + desc = "Positive nether" + elseif -densityNoise > tcave then + desc = "Negative nether" + elseif math_abs(densityNoise) < tmantle then + desc = "Mantle" + + if math_abs(densityNoise) + cavern_noise_adj < mapgen.CENTER_CAVERN_LIMIT then + desc = desc .. " inside cavern" + else + desc = desc .. " but outside cavern" + end + + elseif densityNoise > 0 then + desc = "Shell between positive nether and center region" + else + desc = "Shell between negative nether and center region" + end + + local sea_pos = pos.y - sea_level + if sea_pos > 0 then + desc = desc .. ", " .. sea_pos .. "m above lava-sea level" + else + desc = desc .. ", " .. sea_pos .. "m below lava-sea level" + end + + if tcave_adj > 0 then + desc = desc .. ", approaching y boundary of Nether" + end + + return true, "[Perlin " .. (math_floor(densityNoise * 1000) / 1000) .. "] " .. desc + end + } +) diff --git a/mapgen_nobiomes.lua b/mapgen_nobiomes.lua index 103537d..28792b8 100644 --- a/mapgen_nobiomes.lua +++ b/mapgen_nobiomes.lua @@ -2,6 +2,12 @@ Nether mod for minetest + "mapgen_nobiomes.lua" is the legacy version of the mapgen, only used + in older versions of Minetest or in v6 worlds. + "mapgen.lua" is the modern biomes-based Nether mapgen, which + requires Minetest v5.1 or greater + + Copyright (C) 2013 PilzAdam Permission to use, copy, modify, and/or distribute this software for @@ -190,8 +196,7 @@ minetest.register_on_generated(function(minp, maxp, seed) vm:set_data(data) - -- avoid generating decorations on the underside of the bottom of the nether - if minp.y > NETHER_FLOOR and maxp.y < NETHER_CEILING then minetest.generate_decorations(vm) end + minetest.generate_decorations(vm) vm:set_lighting({day = 0, night = 0}, minp, maxp) vm:calc_lighting() diff --git a/nodes.lua b/nodes.lua index ea94206..2af360e 100644 --- a/nodes.lua +++ b/nodes.lua @@ -75,6 +75,15 @@ minetest.register_node("nether:rack", { sounds = default.node_sound_stone_defaults(), }) +-- Deep Netherrack, found in the mantle / central magma layers +minetest.register_node("nether:rack_deep", { + description = S("Deep-Netherrack"), + tiles = {"nether_rack_deep.png"}, + is_ground_content = true, + groups = {cracky = 3, level = 2}, + sounds = default.node_sound_stone_defaults(), +}) + minetest.register_node("nether:sand", { description = S("Nethersand"), tiles = {"nether_sand.png"}, @@ -95,6 +104,17 @@ minetest.register_node("nether:glowstone", { sounds = default.node_sound_glass_defaults(), }) +-- Deep glowstone, found in the mantle / central magma layers +minetest.register_node("nether:glowstone_deep", { + description = S("Deep-Glowstone"), + tiles = {"nether_glowstone_deep.png"}, + is_ground_content = true, + light_source = 14, + paramtype = "light", + groups = {cracky = 3, oddly_breakable_by_hand = 3}, + sounds = default.node_sound_glass_defaults(), +}) + minetest.register_node("nether:brick", { description = S("Nether Brick"), tiles = {"nether_brick.png"}, @@ -111,6 +131,15 @@ minetest.register_node("nether:brick_compressed", { sounds = default.node_sound_stone_defaults(), }) +-- A decorative node which can only be obtained from dungeons or structures +minetest.register_node("nether:brick_cracked", { + description = S("Cracked Nether Brick"), + tiles = {"nether_brick_cracked.png"}, + is_ground_content = false, + groups = {cracky = 2, level = 2}, + sounds = default.node_sound_stone_defaults(), +}) + local fence_texture = "default_fence_overlay.png^nether_brick.png^default_fence_overlay.png^[makealpha:255,126,126" @@ -169,6 +198,345 @@ if minetest.get_modpath("moreblocks") then end +-- Mantle nodes + +-- Nether basalt is intended as a valuable material and possible portalstone - an alternative to +-- obsidian that's available for other mods to use. +-- It cannot be found in the regions of the nether where Nether portals link to, so requires a journey to obtain. +minetest.register_node("nether:basalt", { + description = S("Blue Basalt"), + tiles = { + "nether_basalt.png", + "nether_basalt.png", + "nether_basalt_side.png", + "nether_basalt_side.png", + "nether_basalt_side.png", + "nether_basalt_side.png" + }, + is_ground_content = true, + groups = {cracky = 1, level = 3}, -- set proper digging times and uses, and maybe explosion immune if api handles that + on_blast = function() --[[blast proof]] end, + sounds = default.node_sound_stone_defaults(), +}) + +-- Potentially a portalstone, but will also be a stepping stone between basalt +-- and chiseled basalt. +-- It can only be introduced by the biomes-based mapgen, since it requires the +-- MT 5.0 world-align texture features. +minetest.register_node("nether:basalt_hewn", { + description = S("Hewn Basalt"), + tiles = {{ + name = "nether_basalt_hewn.png", + align_style = "world", + scale = 2 + }}, + inventory_image = minetest.inventorycube( + "nether_basalt_hewn.png^[sheet:2x2:0,0", + "nether_basalt_hewn.png^[sheet:2x2:0,1", + "nether_basalt_hewn.png^[sheet:2x2:1,1" + ), + is_ground_content = false, + groups = {cracky = 1, level = 2}, + on_blast = function() --[[blast proof]] end, + sounds = default.node_sound_stone_defaults(), +}) + +-- Chiselled basalt is intended as a portalstone - an alternative to obsidian that's +-- available for other mods to use. It is crafted from Hewn Basalt. +-- It should only be introduced by the biomes-based mapgen, since in future it may +-- require the MT 5.0 world-align texture features. +minetest.register_node("nether:basalt_chiselled", { + description = S("Chiselled Basalt"), + tiles = { + "nether_basalt_chiselled_top.png", + "nether_basalt_chiselled_top.png" .. "^[transformFY", + "nether_basalt_chiselled_side.png", + "nether_basalt_chiselled_side.png", + "nether_basalt_chiselled_side.png", + "nether_basalt_chiselled_side.png" + }, + inventory_image = minetest.inventorycube( + "nether_basalt_chiselled_top.png", + "nether_basalt_chiselled_side.png", + "nether_basalt_chiselled_side.png" + ), + paramtype2 = "facedir", + is_ground_content = false, + groups = {cracky = 1, level = 2}, + on_blast = function() --[[blast proof]] end, + sounds = default.node_sound_stone_defaults(), +}) + + +-- Lava-sea source +-- This is a lava source using a different animated texture so that each node +-- is out of phase in its animation from its neighbor. This prevents the magma +-- ocean from visually clumping together into a patchwork of 16x16 squares. +-- It can only be used by the biomes-based mapgen, since it requires the MT 5.0 +-- world-align texture features. +local lavasea_source = {} +local lava_source = minetest.registered_nodes["default:lava_source"] +for key, value in pairs(lava_source) do lavasea_source[key] = value end +lavasea_source.name = nil +lavasea_source.tiles = { + { + name = "nether_lava_source_animated.png", + backface_culling = false, + align_style = "world", + scale = 2, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 3.0, + }, + }, + { + name = "nether_lava_source_animated.png", + backface_culling = true, + align_style = "world", + scale = 2, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 3.0, + }, + }, +} +lavasea_source.liquid_alternative_source = "nether:lava_source" +lavasea_source.inventory_image = minetest.inventorycube( + "nether_lava_source_animated.png^[sheet:2x16:0,0", + "nether_lava_source_animated.png^[sheet:2x16:0,1", + "nether_lava_source_animated.png^[sheet:2x16:1,1" +) +minetest.register_node("nether:lava_source", lavasea_source) + + +-- a place to store the original ABM function so nether.cool_lava() can call it +local original_cool_lava_action + +nether.cool_lava = function(pos, node) + + local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z} + local node_above = minetest.get_node(pos_above) + + -- Evaporate water sitting above lava, if it's in the Nether. + -- (we don't want Nether mod to affect overworld lava mechanics) + if minetest.get_node_group(node_above.name, "water") > 0 and + pos.y < nether.DEPTH_CEILING and pos.y > nether.DEPTH_FLOOR then + -- cools_lava might be a better group to check for, but perhaps there's + -- something in that group that isn't a liquid and shouldn't be evaporated? + minetest.swap_node(pos_above, {name="air"}) + end + + -- add steam to cooling lava + minetest.add_particlespawner({ + amount = 20, + time = 0.15, + minpos = {x=pos.x - 0.4, y=pos.y - 0, z=pos.z - 0.4}, + maxpos = {x=pos.x + 0.4, y=pos.y + 0.5, z=pos.z + 0.4}, + minvel = {x = -0.5, y = 0.5, z = -0.5}, + maxvel = {x = 0.5, y = 1.5, z = 0.5}, + minacc = {x = 0, y = 0.1, z = 0}, + maxacc = {x = 0, y = 0.2, z = 0}, + minexptime = 0.5, + maxexptime = 1.3, + minsize = 1.5, + maxsize = 3.5, + texture = "nether_particle_anim4.png", + animation = { + type = "vertical_frames", + aspect_w = 7, + aspect_h = 7, + length = 1.4, + } + }) + + if node.name == "nether:lava_source" or node.name == "nether:lava_crust" then + -- use swap_node to avoid triggering the lava_crust's after_destruct + minetest.swap_node(pos, {name = "nether:basalt"}) + + minetest.sound_play("default_cool_lava", + {pos = pos, max_hear_distance = 16, gain = 0.25}, true) + else + -- chain the original ABM action to handle conventional lava + original_cool_lava_action(pos, node) + end +end + + +minetest.register_on_mods_loaded(function() + + -- register a bucket of Lava-sea source - but make it just the same bucket as default lava. + -- (by doing this in register_on_mods_loaded we don't need to declare a soft dependency) + if minetest.get_modpath("bucket") and minetest.global_exists("bucket") then + local lava_bucket = bucket.liquids["default:lava_source"] + if lava_bucket ~= nil then + local lavasea_bucket = {} + for key, value in pairs(lava_bucket) do lavasea_bucket[key] = value end + lavasea_bucket.source = "nether:lava_source" + bucket.liquids[lavasea_bucket.source] = lavasea_bucket + end + end + + -- include "nether:lava_source" in any "default:lava_source" ABMs + local function include_nether_lava(set_of_nodes) + if (type(set_of_nodes) == "table") then + for _, nodename in pairs(set_of_nodes) do + if nodename == "default:lava_source" then + -- I'm amazed this works, but it does + table.insert(set_of_nodes, "nether:lava_source") + break; + end + end + end + end + + for _, abm in pairs(minetest.registered_abms) do + include_nether_lava(abm.nodenames) + include_nether_lava(abm.neighbors) + if abm.label == "Lava cooling" and abm.action ~= nil then + -- lets have lava_crust cool as well + original_cool_lava_action = abm.action + abm.action = nether.cool_lava + table.insert(abm.nodenames, "nether:lava_crust") + end + end + for _, lbm in pairs(minetest.registered_lbms) do + include_nether_lava(lbm.nodenames) + end + --minetest.log("minetest.registered_abms" .. dump(minetest.registered_abms)) + --minetest.log("minetest.registered_lbms" .. dump(minetest.registered_lbms)) +end) + +-- creates a lava splash, and leaves lava_source in place of the lava_crust +local function smash_lava_crust(pos, playsound) + + local lava_particlespawn_def = { + amount = 6, + time = 0.1, + minpos = {x=pos.x - 0.5, y=pos.y + 0.3, z=pos.z - 0.5}, + maxpos = {x=pos.x + 0.5, y=pos.y + 0.5, z=pos.z + 0.5}, + minvel = {x = -1.5, y = 1.5, z = -1.5}, + maxvel = {x = 1.5, y = 5, z = 1.5}, + minacc = {x = 0, y = -10, z = 0}, + maxacc = {x = 0, y = -10, z = 0}, + minexptime = 1, + maxexptime = 1, + minsize = .2, + maxsize = .8, + texture = "^[colorize:#A00:255", + glow = 8 + } + minetest.add_particlespawner(lava_particlespawn_def) + lava_particlespawn_def.texture = "^[colorize:#FB0:255" + lava_particlespawn_def.maxvel.y = 3 + lava_particlespawn_def.glow = 12 + minetest.add_particlespawner(lava_particlespawn_def) + + minetest.set_node(pos, {name = "default:lava_source"}) + + if math.random(1, 3) == 1 and minetest.registered_nodes["fire:basic_flame"] ~= nil then + -- occasionally brief flames will be seen when breaking lava crust + local posAbove = {x = pos.x, y = pos.y + 1, z = pos.z} + if minetest.get_node(posAbove).name == "air" then + minetest.set_node(posAbove, {name = "fire:basic_flame"}) + minetest.get_node_timer(posAbove):set(math.random(7, 15) / 10, 0) + --[[ commented out because the flame sound plays for too long + if minetest.global_exists("fire") and fire.update_player_sound ~= nil then + -- The fire mod only updates its sound every 3 seconds, these flames will be + -- out by then, so start the sound immediately + local players = minetest.get_connected_players() + for n = 1, #players do fire.update_player_sound(players[n]) end + end]] + end + end + + if playsound then + minetest.sound_play( + "nether_lava_bubble", + -- this sample was encoded at 3x speed to reduce .ogg file size + -- at the expense of higher frequencies, so pitch it down ~3x + {pos = pos, pitch = 0.3, max_hear_distance = 8, gain = 0.4} + ) + end +end + + +-- lava_crust nodes can only be used in the biomes-based mapgen, since they require +-- the MT 5.0 world-align texture features. +minetest.register_node("nether:lava_crust", { + description = "Lava crust", + tiles = { + { + name="nether_lava_crust_animated.png", + backface_culling=true, + tileable_vertical=true, + tileable_horizontal=true, + align_style="world", + scale=2, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 1.8, + }, + } + }, + inventory_image = minetest.inventorycube( + "nether_lava_crust_animated.png^[sheet:2x48:0,0", + "nether_lava_crust_animated.png^[sheet:2x48:0,1", + "nether_lava_crust_animated.png^[sheet:2x48:1,1" + ), + collision_box = { + type = "fixed", + fixed = { + -- Damage is calculated "starting 0.1 above feet + -- and progressing upwards in 1 node intervals", so + -- lower this node's collision box by more than 0.1 + -- to ensure damage will be taken when standing on + -- the node. + {-0.5, -0.5, -0.5, 0.5, 0.39, 0.5} + }, + }, + selection_box = { + type = "fixed", + fixed = { + -- Keep the selection box matching the visual node, + -- rather than the collision_box. + {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5} + }, + }, + + after_destruct = function(pos, oldnode) + smash_lava_crust(pos, true) + end, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + end, + on_blast = function(pos, intensity) + smash_lava_crust(pos, false) + end, + + paramtype = "light", + light_source = default.LIGHT_MAX - 3, + buildable_to = false, + walkable_to = true, + is_ground_content = true, + drop = { + items = {{ + -- Allow SilkTouch-esque "pickaxes of preservation" to mine the lava crust intact, if PR #10141 gets merged. + tools = {"this line will block early MT versions which don't respect the tool_groups restrictions"}, + tool_groups = {{"pickaxe", "preservation"}}, + items = {"nether:lava_crust"} + }} + }, + --liquid_viscosity = 7, + damage_per_second = 2, + groups = {oddly_breakable_by_hand = 3, cracky = 3, explody = 1, igniter = 1}, +}) + + -- Fumaroles (Chimney's) local function fumarole_startTimer(pos, timeout_factor) @@ -393,31 +761,3 @@ local airlike_darkness = {} for k,v in pairs(minetest.registered_nodes["air"]) do airlike_darkness[k] = v end airlike_darkness.paramtype = "none" minetest.register_node("nether:airlike_darkness", airlike_darkness) - - --- Crafting - -minetest.register_craft({ - output = "nether:brick 4", - recipe = { - {"nether:rack", "nether:rack"}, - {"nether:rack", "nether:rack"}, - } -}) - -minetest.register_craft({ - output = "nether:fence_nether_brick 6", - recipe = { - {"nether:brick", "nether:brick", "nether:brick"}, - {"nether:brick", "nether:brick", "nether:brick"}, - }, -}) - -minetest.register_craft({ - output = "nether:brick_compressed", - recipe = { - {"nether:brick","nether:brick","nether:brick"}, - {"nether:brick","nether:brick","nether:brick"}, - {"nether:brick","nether:brick","nether:brick"}, - } -}) diff --git a/sounds/nether_lava_bubble.0.ogg b/sounds/nether_lava_bubble.0.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4eeef69e697807fb3ff092adefafb01bebe62a75 GIT binary patch literal 7604 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 M07*qoM6N<$g1Ff;M*si- literal 0 HcmV?d00001 diff --git a/textures/nether_basalt_chiselled_side.png b/textures/nether_basalt_chiselled_side.png new file mode 100644 index 0000000000000000000000000000000000000000..46a173a16d6712dbe6b8b295f26af9e03daa8ebe GIT binary patch literal 597 zcmV-b0;>IqP)NmUZnaxtow86-g>` zUAGUAq`F;oJ)gI#3#4K!%bx4D1K9WXaIDj zZW%JlfK6in0;q^k3Z&ihdZ8Nty4)v;%q4S#w605hP9m9eUX*fdiu8H3yXxwmcG*^@ z0e8)L9>?9?ImQNnBnUA`NeK`LfL#UvO3E?b42YuL0Npk~s=GiLHrzeCiWG@Y)K&Pb z@bdiA^fDuEmK@b2;0-y~W0L7#T^luM$SH4~kMV#le+W<+891%gP zYGy7}c2&*uc-*>M``gzswsreMlDp@1+;4x)d0po*=UG)5BXUth=E%&97*YVRiv&dp zB%};?WJWGh00d|tZMVCsY#K0VsH&Ph&)185L|*3uF3D0PMHVuLB!Hn<#xlkVpsL2Q zDHcH8KCkKSJf3$FRTC6|>e+7FfC*BuZtwB%ckxBWkI7cRB%IMD+D001R)MObt} za&&2PbO2OxWo2?8XmoUNb2=|CXK8e3bz&}KZ*4DBa%E+5*@TPy0000KbVXQnLvL_- ja%pF1bO16iGBF@ja%E+5^W4i%00000NkvXXu0mjfr!N9K literal 0 HcmV?d00001 diff --git a/textures/nether_basalt_chiselled_top.png b/textures/nether_basalt_chiselled_top.png new file mode 100644 index 0000000000000000000000000000000000000000..3d6a70e63bfd7adc77f0ff868e4c68cdd280c850 GIT binary patch literal 594 zcmV-Y0JJbD_ zvMb#1+f@xDiK-i<$M#B0N-EXXwXb!M0$JT8r2=SA zCu0xE`~5pXPyk6v1b`sOhjP6>N$dm(o}Pc70r}}I)mjgL00JO5j(b9Yy=@nJwyy4~ z>My^2B}CQZ@$R+8ORBfG{}Lxls{Yto+YaFU{r{Pxsy(x2D2esUudlWf+mpCS0hkp4 zfT+#mANM-}5ZCLoL`j6mvPVe*%pA5!68!S=$Mt%<+@2Bum>GbeRG$IQIx;IB&q@qP z)gB}HC%{qZColVjr0Pj^xm<44w$AfBABh2g-(q{FyLSNRI_-NLXS({mdf#tr zok{FTP%2QM8VE_Sy0+N%*fZyO9*0U&Q40jGW zl2Ny+GK z>qc_Mz1CyxC#fV!07#w0*$zliB1sYnfZNM$_DHmiWUr6}wf9pjh@=pBOfpFWA~3T^ zl8T*dsjlm#YT{8f$WnpaYayYEtn1|>5Cni{+Y_6RkN{LkvfXPvAQc5*W+$eT*d9{q zPLNr9J!bZLK3`v7k%WmSfbC@BfJ^`<0#!e&^~=la<8gOJQmMuudB6bReg7y)WF=Z_ z&A6}2vsG1fkqt00S+)~9Va>+uK(lvE$i! z0s;>ffCR8e^^N2>4MeK5-XxO1M#i>h2s!~-)d-xBgcBq&z&OE{N)m8tkiv3P}RblN6~0Bm+y;_qYF!Lzb$Kl9@gG*?rx5J!W?=`c}Ln*U?i0JN_Ju@hjn)R~x0*s)m3G&mgzY|n< zsrFupNmgC<00C6po*g^D?A3h>f`9}Fsb@BUBb2cnAJqy7q(6WDi>l**0y48^FMEG@ zd0qP{GMU?lTawuL@C%SqRo_6_+q3MJy1GOKlq#MeNWOgecLVzJTtlz@yrYWk$bj1>-p?tBXhOLcgBNE^78WG zkaK1rRuu{R@|nWSL6_~!cs~ybVpl1U7)rUi14<1lKSYjFsn)vN0uY4Y7+qIF1~Xey zyb&Mv@mIldihDS8P?`GyqSZb5tH3^ynhr|4WN!3>4+0Rkz9- zn*>l)c?{L1pDItW44>WHZl8j;swR;*!8rB?aLf%!Rd*E-JgCGVJnOKWpsJ1)CqAkh zkgUFLv5&X`1emn^aX7!FW8|-h1!Y*N-#fSwJKakgBSyE+CnabkJ4RWVP7Ux2mpp)%-~~RcU6D zO;V-AXO|?Yde12;vJ$WLIHook5d)lA^!$J_xd}>r%DHwiBLOGntv|dU-yV z4$R(p>o_98kj#mMco&lH+lL(60%m6K=XDi{?rY^)-6w$&IZplk`?tsAF7e1B`;vOk z(+N-~vL&eZBw+sO^Ir*8HLE=PK=7nNN>xqDv1bENwP&AHN)V{RB~lyav*4QbZ~PzFE3|lbZB*AE@N+PFH~}6 zWpdesi~Ilp02FjZSad^gaCvfRXJ~W)GB7eRAXIW?WpeY}%TE9R002ovPDHLkV1jxp B{n`Kk literal 0 HcmV?d00001 diff --git a/textures/nether_basalt_side.png b/textures/nether_basalt_side.png new file mode 100644 index 0000000000000000000000000000000000000000..7c33847e7f69df7fb2ae35db6dc1ae0201d729c3 GIT binary patch literal 518 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GG!XV7ZFl&wk0|R5a zr;B5V#(CRGXY)iHc$)tj-xgcZawV?v|8wV#OR42a#WO@LpMFr?H21^XzsEm+zTV$I zfBpLW>*wRE@9(eqJ@4kG+4tUGU%q_$nYiiGUq8?HQo86CB)wk!=FDCtV+M`4wfZ;s zRywcSwkX|9^CE)-Lx%G&pKT0XZc`>NobhJc7Dk2~ZzJQQ&8#zBX5M8okymKg#(IOL z;|UXk=PmD-GSZnIs?0V$zRP@PH+!?~a#@(m6e7Nrm2<;g_DMdwW-bn1(!{Xz3g6O{ z#mbTkws5FzH#>R4+ktal>JmR0PX-S!w{QO)T)CG=RWdH^P?DU$kaldJOulZ$>y2A2 zUru0i`p_}0WcS~Ru0}U~U02hqEHk-FAC2jTECuWn3C*M?=tmrtWZPJ@ig_}%HMQWeC z)J`&TiDWogb#7rvdnW&o-`el^12airJgAnqMwB=fm1Gu|FoYDPrWPq=l#~<{Tj}ek zXO?7?Cg~;T=jwwcZnkv)0csEdX>iUjs4U7%&nRIqGB7e!0Ly>AbJ`y$&*16m=d#Wz Gp$PyB5!4(2 literal 0 HcmV?d00001 diff --git a/textures/nether_brick_cracked.png b/textures/nether_brick_cracked.png new file mode 100644 index 0000000000000000000000000000000000000000..1729b2caa6a7bca80e641d3a439ee978e166b71b GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHF4e$wZjW9F})YJ3U*7noYb=TB% zQd6^2QSs2yvQ}2MS5vcAQ886i)RvYuQ&KXJmp5kBJp|OqS>O>_%)r1c48n{Iv*t(u z1!sG@IEHXsXPm&0|DS<@F@S-AnL&i1UC^~qNl;LM;oaHgw|7qQRAe|C9yw{>%UMng zJ6Ek*>GgW13d73K$eHtkS`rvuMy*=ez3R?GhTXg0t=`?y-2^n2QQXK-z<@zXNkxg% zC1euA+FR8VIb5S>GPqZBxXA5zzJwvXuzMr3wdG8PRZGpEh^lm!GL+7AuHjxeGo0bv fz1{ERUcb91P;BwPpLc00&^!iDS3j3^P6pHOi4sRR4C6)kD58;vA{1PFG4T~mqe#LmgjkVp5;ha^?0 zRQce_CaJ{1n_UoyMF{;dn#sXFxbJ=Gma}mHG3rc1=5+@o=vAo5-*Zq9Pl**&27w~Np}049|SkkVd`UjrJS|bNiYsj0w4n5 z3xFpm1V^C#Nq`8}p~5g62M7SxVJw0Aq5;-ghg)8yT45cJWv{O%LoEQihFww5Mv)1K zeSlNP;cyUSm4*VwaVXCEDpG)hP0^G^=}?cCOVcz_6xB_0JRX6p>=vVNTe)4HOL=i^ z&*p6RPp9XLNgC2y)+e{y?W(5kjq$ZV7!1ba(RP~+LtlRS=hzzCwe5@5^4kQZa9}Kz z;jgSN%Q8*V<;XXdyy_kvHu}HK_GYU}_OD9Pj?ek+*SFgT%c^ga7xy`ZNAM(EMUw*UlJXM}+Idu-m&+V^w zYhX5={ctn-JaWA|Z}O)f-#iy3zx=V$p4WEW|E>5u@8Flle*gdg07*qoM6N<$g0Or- Aj{pDw literal 0 HcmV?d00001 diff --git a/textures/nether_lava_crust_animated.png b/textures/nether_lava_crust_animated.png new file mode 100644 index 0000000000000000000000000000000000000000..f8f8c25a0a4027ee47ebbd5cd8fb76b82408ab36 GIT binary patch literal 18533 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 JJp0)#@^9EE^5_5n literal 0 HcmV?d00001 diff --git a/textures/nether_particle_anim4.png b/textures/nether_particle_anim4.png new file mode 100644 index 0000000000000000000000000000000000000000..0f1b849a449365aa0770625b80367172f2332982 GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^>_Du=!VDyP{bD$P6id3JuOkD)#(wTUiL5|AV{wqX z6T`Z5GB1G~p#Yx{SN8&+|EQot(xx6L%UTlT7tCNkWvaug%LkVN1-v|6978y+PwhF# zd%%E)>3rDd?;4V=f0t)AP1;r|*4ciR(UB=v!gTk7)B0;0EG9%QaGN2YqGf(b|9;Wt z^$#MAf^t~o4=V0m{b+jLdlA-Z(@&q9fTpUJxJHyX7L{ZcmoS7BrKT1sWR#Q?6kF-* zr)QRAlqTsV=jZB!C2qEK{{dgTe~ HDWM4f)Glgu literal 0 HcmV?d00001 diff --git a/textures/nether_rack_deep.png b/textures/nether_rack_deep.png new file mode 100644 index 0000000000000000000000000000000000000000..69bb7c29c6bb2734a66423128077aea51bc7637a GIT binary patch literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJXMsm#F#`j)AP6(or^HVL3Wf*x zgt#gw*eWX7DJwgus5q*rI%#OQXllA?YP)OecFW9D8Tc9)_!}Df8yN+dm;{@e z1Y1}{SXxEd*v8u0#o5~@IXEOcI;Oh1WVpHKczPE2`V|ESSL*fu+6J^@gQtsQh=io* zLGC0cMIM#|D_9R555F-%b=%(mmaC0FaT&xo3m!7VbUWe+t6ddypw=qNmC?b0blcKOmld6Dc4 zvu4c=I~q{T_#$srE{~yc?HS8T{iDDBh@HC`;c-{}-yOx07aM}gCX~D{`eXLI=)Vzz u+w@Nwvht!2zX!FpzdRImts?aI#QIs?{D051n(zSK&fw|l=d#Wzp$P#0ID3Zx literal 0 HcmV?d00001 diff --git a/tools.lua b/tools.lua index 637cdf0..26e1425 100644 --- a/tools.lua +++ b/tools.lua @@ -1,3 +1,22 @@ +--[[ + + Copyright (C) 2020 lortas + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + +]]-- + local S = nether.get_translator minetest.register_tool("nether:pick_nether", { From 24845dce1eeac3e17df912a98709b45f0c00e58e Mon Sep 17 00:00:00 2001 From: Treer Date: Thu, 7 Jan 2021 23:48:00 +1100 Subject: [PATCH 2/3] Update descriptions --- locale/nether.fr.tr | 161 +++++++++++++++++++++++++++----------------- locale/template.txt | 159 ++++++++++++++++++++++++++----------------- mapgen.lua | 2 +- nodes.lua | 24 +++++-- 4 files changed, 215 insertions(+), 131 deletions(-) diff --git a/locale/nether.fr.tr b/locale/nether.fr.tr index f34afd9..48201d8 100644 --- a/locale/nether.fr.tr +++ b/locale/nether.fr.tr @@ -1,62 +1,99 @@ -# textdomain: nether - -# Translation FR by Louis Royer - - -### init.lua ### - -Construction requires 14 blocks of obsidian, which we found deep underground where water had solidified molten rock. The finished frame is four blocks wide, five blocks high, and stands vertically, like a doorway.@n@nThis opens to a truly hellish place, though for small mercies the air there is still breathable. There is an intriguing dimensional mismatch happening between this realm and ours, as after opening the second portal into it we observed that 10 strides taken in the Nether appear to be an equivalent of @1 in the natural world.@n@nThe 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.=Cette construction nécessite 14 blocs d’obsidienne, qui peut être trouvée profondément sous terre, là où l’eau a solidifié de la roche fondue. Une fois terminé, le cadre fait quatre blocs de large, cinq blocs de haut, et se tient verticalement comme une porte.@n@nElle ouvre sur un lieu vraiment infernal, mais on peut s’estimer heureux que l’air y soit quand même respirable. Il y a un décalage dimensionnel intrigant entre ce monde et le nôtre, car après avoir ouvert un deuxième portail, nous avons observé que 10 pas effectués dans le Nether semblent être l’équivalent de @1 dans notre monde.@n@nLes membres de l’expédition n’ontr trouvé ni diamants ni or, et après qu’un groupe de recheche expérimenté n’ait pas réussi à retrouver la piste d’un membre de l’expédition disparu, je n’ai d’autre choix que de conclure que cet endroit est trop dangereux pour nous. - - -### init.lua ### -### nodes.lua ### - -Nether Portal=Portail du Nether - -### nodes.lua ### - -Glowstone=Pierre lumineuse -Inner Nether Stair=Escalier intérieur du Nether -Nether Brick=Brique du Nether -Nether Brick Fence=Barrière en briques du Nether -Nether Slab=Dalle du Nether -Nether Stair=Escalier du Nether -Netherrack=Roche du Nether -Nethersand=Sable du Nether -Outer Nether Stair=Escalier extérieur du Nether - -### portal_api.lua ### - -@n@nThe key to opening such a doorway is to strike the frame with a @1, at which point the very air inside begins to crackle and glow.=@n@nLa méthode pour ouvrir une telle porte est de frapper son cadre avec un @1, jusqu’à ce que tout l’air à l’intérieur commence à crépiter et briller. - -A definitive guide to Rifts and Portals=Un guide détaillé des failles et des portails - -A guidebook for how to build portals to other realms. It can sometimes be found in dungeon chests, however a copy of this book is not needed as its contents are included in this Encyclopedia.=Un guide sur comment construire des portails vers d’autres mondes. Il peut parfois être trouvé dans des coffres de dongeons, cependant la copie de ce livre n’est pas nécessaire puisque son contenu est inclus dans l’encyclopédie. - -Book of Portals=Livre des portails -Building Portals=Construire des portails - -In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only @1 can I confirm as being more than merely stories.=Après tous mes voyages, et le temps passé dans les Grandes Bibliothèques, je ne manque pas de légendes sur les portes surnaturelles qui, dit-on s’ouvrent vers d’autres mondes, mais seul @1 peut confirmer que ce sont plus que de simples histoires. - -In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only one can I confirm as being more than merely a story.=Après tous mes voyages, et le temps passé dans les Grandes Bibliothèques, je ne manque pas de légendes sur les portes surnaturelles qui, dit-on s’ouvrent vers d’autres mondes, mais seul une personne peut confirmer que ce sont plus que de simples histoires. - -Portal wormhole=Vortex du portail - -Portals to other realms can be opened by building a frame in the right shape with the right blocks, then using an item to activate it. A local copy of the guidebook to portals is published below.@n---@n@n=Les portails vers d’autres mondes peuvent être ouvert en construisant un cadre de la bonne forme avec les bons blocs, puis en utilisant un objet pour l’activer. Une copie du guide des portails est ci-dessous.@n---@n@n - -Refer: "Help" > "Basics" > "Building Portals"=Voir : Aide > Bases > Construire des portails -Untitled portal=Portail sans nom -We know almost nothing about this portal=Nous ne savons presque rien sur les portails - -### portal_examples.lua ### - -Floatlands Portal=Portail du monde flottant - -Requiring 16 blocks of tin and constructed in a circular fashion, a finished frame is seven blocks wide, seven blocks high, and stands vertically like a doorway.@n@nThese travel a distance along the ground, and even when constructed deep underground will link back up to the surface. They appear to favor a strange direction, with the exit portal linking back only for as long as the portal stays open — attempting to reopen a portal from the exit doorway leads to a new destination along this favored direction. It has stymied our ability to study the behavior of these portals because without constructing dual portals and keeping both open it's hard to step through more than one and still be able to return home.@n@nDue to such difficulties, we never learned what determines the direction and distance where the matching twin portal will appear, and I have lost my friend and protégé. In cavalier youth and with little more than a rucksack, Coudreau has decided to follow the chain as far as it goes, and has not been seen since. Coudreau believes it works in epicycles, but I am not convinced. Still, I cling to the hope that one day the portal will open and Coudreau will step out from whichever place leads to this one, perhaps with an epic tale to tell.=Nécessite 16 blocs d’étain placés de manière circulaire, le cadre final fait sept blocs de large, sept blocs de haut, et se tient verticalement comme une porte.@n@nIls permettent de voyager une distance sous le sol et se relieent à la surface même s’ils sont construits profondément sous terre. Ils ont l’air de préférer une direction étrange, avec le portail de sortie ne se reliant au portail d’entrée que tant qu’ils restent tous deux ouverts – tenter de réouvrir le portail de sortie mènera à une nouvelle destination dans cette direction privilégiée.Cela a entravé notre capacité à étudier le comportement de ces portails, car sans la construction de doubles portails et en gardant les deux ouverts, il est difficile d'en traverser plus d'un et de pouvoir rentrer chez soi.@n@nEn raison de ces difficultés, nous n'avons jamais appris ce qui détermine la direction et la distance à laquelle le portail jumeau correspondant apparaîtra, et j’ai perdu mon ami et mon protégé. Dans sa jeunesse cavalière et avec à peine plus qu'un sac à dos, Coudreau a décidé de suivre la chaîne jusqu'au bout, et n'a pas été vu depuis. Coudreau croit qu'elle fonctionne sur les épicycles, mais je n'en suis pas convaincu. Je m'accroche néanmoins à l'espoir qu'un jour le portail s'ouvrira et que Coudreau sortira de l'endroit qui mène à celui-ci, peut-être avec un récit épique à raconter. - -Requiring 21 blocks of ice, and constructed in the shape of a 3 × 3 platform with walls, or like a bowl. A finished platform is 2 blocks high, and 5 blocks wide at the widest in both directions.@n@nThis portal is different to the others, rather than acting akin to a doorway it appears to the eye more like a small pool of water which can be stepped into. Upon setting foot in the portal we found ourselves at a tremendous altitude.@1=Nécessite 21 blocs de glace placés pour former une plateforme de 3 × 3 avec des murs, ou comme un bol. La plateforme finale fait 2 blocs de haut, et 5 blocs de large à sa largeur maximale dans les deux directions.@n@nCe portail est différent des autres, au lieu de ressembler à une porte, il ressemble plus à un petit bassin d’eau dans lequel on peut entrer. En mettant les pieds dans le portail, nous nous sommes retrouvés à une altitude énorme.@1 - -Surface Portal=Portail de surface - -There is a floating land of hills and forests up there, over the edges of which is a perilous drop all the way back down to sea level. We have not found how far these pristine lands extend. I have half a mind to retire there one day.=Il y a là un monde flottant remplis de collines et de forêts, sur les bords duquel se trouve une chute périlleuse jusqu'au niveau de la mer. Nous n'avons pas encore trouvé jusqu'où s'étendent ces terres vierges. J'ai à moitié envie de m'y retirer un jour. - +# textdomain: nether + +# Translation FR by Louis Royer + + +### init.lua ### + +Construction requires 14 blocks of obsidian, which we found deep underground where water had solidified molten rock. The finished frame is four blocks wide, five blocks high, and stands vertically, like a doorway.@n@nThis opens to a truly hellish place, though for small mercies the air there is still breathable. There is an intriguing dimensional mismatch happening between this realm and ours, as after opening the second portal into it we observed that 10 strides taken in the Nether appear to be an equivalent of @1 in the natural world.@n@nThe 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.=Cette construction nécessite 14 blocs d’obsidienne, qui peut être trouvée profondément sous terre, là où l’eau a solidifié de la roche fondue. Une fois terminé, le cadre fait quatre blocs de large, cinq blocs de haut, et se tient verticalement comme une porte.@n@nElle ouvre sur un lieu vraiment infernal, mais on peut s’estimer heureux que l’air y soit quand même respirable. Il y a un décalage dimensionnel intrigant entre ce monde et le nôtre, car après avoir ouvert un deuxième portail, nous avons observé que 10 pas effectués dans le Nether semblent être l’équivalent de @1 dans notre monde.@n@nLes membres de l’expédition n’ontr trouvé ni diamants ni or, et après qu’un groupe de recheche expérimenté n’ait pas réussi à retrouver la piste d’un membre de l’expédition disparu, je n’ai d’autre choix que de conclure que cet endroit est trop dangereux pour nous. + + +### init.lua ### +### nodes.lua ### + +Nether Portal=Portail du Nether + +### nodes.lua ### + += +A finely finished block of solid Nether Basalt.= +A rough cut solid block of Nether Basalt.= +A thin crust of cooled lava with liquid lava beneath= +A vent in the earth emitting steam and gas= +Can be repurposed to provide puffs of smoke in a chimney= +Chiselled Basalt= + +Columns of dark basalt found only in magma oceans deep within the Nether.= + +Compressed Netherbrick= +Cracked Nether Brick= +Deep Glowstone= +Deep Netherrack= +Fumarolic Chimney= +Fumarolic Chimney Corner= +Fumarolic Chimney Slab= +Glowstone=Pierre lumineuse +Hewn Basalt= +Inner Nether Stair=Escalier intérieur du Nether +Lava Crust= + +Lava crust is strong enough to walk on, but still hot enough to inflict burns.= + +Nether Basalt= +Nether Brick=Brique du Nether +Nether Brick Fence=Barrière en briques du Nether +Nether Slab=Dalle du Nether +Nether Stair=Escalier du Nether +Netherrack=Roche du Nether +Netherrack from deep in the mantle= +Netherrack stair= +Nethersand=Sable du Nether +Outer Nether Stair=Escalier extérieur du Nether +Portal= + +### portal_api.lua ### + +@n@nThe key to opening such a doorway is to strike the frame with a @1, at which point the very air inside begins to crackle and glow.=@n@nLa méthode pour ouvrir une telle porte est de frapper son cadre avec un @1, jusqu’à ce que tout l’air à l’intérieur commence à crépiter et briller. + +A definitive guide to Rifts and Portals=Un guide détaillé des failles et des portails + +A guidebook for how to build portals to other realms. It can sometimes be found in dungeon chests, however a copy of this book is not needed as its contents are included in this Encyclopedia.=Un guide sur comment construire des portails vers d’autres mondes. Il peut parfois être trouvé dans des coffres de dongeons, cependant la copie de ce livre n’est pas nécessaire puisque son contenu est inclus dans l’encyclopédie. + +Book of Portals=Livre des portails +Building Portals=Construire des portails + +In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only @1 can I confirm as being more than merely stories.=Après tous mes voyages, et le temps passé dans les Grandes Bibliothèques, je ne manque pas de légendes sur les portes surnaturelles qui, dit-on s’ouvrent vers d’autres mondes, mais seul @1 peut confirmer que ce sont plus que de simples histoires. + +In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only one can I confirm as being more than merely a story.=Après tous mes voyages, et le temps passé dans les Grandes Bibliothèques, je ne manque pas de légendes sur les portes surnaturelles qui, dit-on s’ouvrent vers d’autres mondes, mais seul une personne peut confirmer que ce sont plus que de simples histoires. + +Mysterious forces prevented you from opening that portal. Please try another location= + +Portal wormhole=Vortex du portail + +Portals to other realms can be opened by building a frame in the right shape with the right blocks, then using an item to activate it. A local copy of the guidebook to portals is published below.@n---@n@n=Les portails vers d’autres mondes peuvent être ouvert en construisant un cadre de la bonne forme avec les bons blocs, puis en utilisant un objet pour l’activer. Une copie du guide des portails est ci-dessous.@n---@n@n + +Refer: "Help" > "Basics" > "Building Portals"=Voir : Aide > Bases > Construire des portails +Untitled portal=Portail sans nom +We know almost nothing about this portal=Nous ne savons presque rien sur les portails + +### portal_examples.lua ### + +Floatlands Portal=Portail du monde flottant + +Requiring 16 blocks of tin and constructed in a circular fashion, a finished frame is seven blocks wide, seven blocks high, and stands vertically like a doorway.@n@nThese travel a distance along the ground, and even when constructed deep underground will link back up to the surface. They appear to favor a strange direction, with the exit portal linking back only for as long as the portal stays open — attempting to reopen a portal from the exit doorway leads to a new destination along this favored direction. It has stymied our ability to study the behavior of these portals because without constructing dual portals and keeping both open it's hard to step through more than one and still be able to return home.@n@nDue to such difficulties, we never learned what determines the direction and distance where the matching twin portal will appear, and I have lost my friend and protégé. In cavalier youth and with little more than a rucksack, Coudreau has decided to follow the chain as far as it goes, and has not been seen since. Coudreau believes it works in epicycles, but I am not convinced. Still, I cling to the hope that one day the portal will open and Coudreau will step out from whichever place leads to this one, perhaps with an epic tale to tell.=Nécessite 16 blocs d’étain placés de manière circulaire, le cadre final fait sept blocs de large, sept blocs de haut, et se tient verticalement comme une porte.@n@nIls permettent de voyager une distance sous le sol et se relieent à la surface même s’ils sont construits profondément sous terre. Ils ont l’air de préférer une direction étrange, avec le portail de sortie ne se reliant au portail d’entrée que tant qu’ils restent tous deux ouverts – tenter de réouvrir le portail de sortie mènera à une nouvelle destination dans cette direction privilégiée.Cela a entravé notre capacité à étudier le comportement de ces portails, car sans la construction de doubles portails et en gardant les deux ouverts, il est difficile d'en traverser plus d'un et de pouvoir rentrer chez soi.@n@nEn raison de ces difficultés, nous n'avons jamais appris ce qui détermine la direction et la distance à laquelle le portail jumeau correspondant apparaîtra, et j’ai perdu mon ami et mon protégé. Dans sa jeunesse cavalière et avec à peine plus qu'un sac à dos, Coudreau a décidé de suivre la chaîne jusqu'au bout, et n'a pas été vu depuis. Coudreau croit qu'elle fonctionne sur les épicycles, mais je n'en suis pas convaincu. Je m'accroche néanmoins à l'espoir qu'un jour le portail s'ouvrira et que Coudreau sortira de l'endroit qui mène à celui-ci, peut-être avec un récit épique à raconter. + +Requiring 21 blocks of ice, and constructed in the shape of a 3 × 3 platform with walls, or like a bowl. A finished platform is 2 blocks high, and 5 blocks wide at the widest in both directions.@n@nThis portal is different to the others, rather than acting akin to a doorway it appears to the eye more like a small pool of water which can be stepped into. Upon setting foot in the portal we found ourselves at a tremendous altitude.@1=Nécessite 21 blocs de glace placés pour former une plateforme de 3 × 3 avec des murs, ou comme un bol. La plateforme finale fait 2 blocs de haut, et 5 blocs de large à sa largeur maximale dans les deux directions.@n@nCe portail est différent des autres, au lieu de ressembler à une porte, il ressemble plus à un petit bassin d’eau dans lequel on peut entrer. En mettant les pieds dans le portail, nous nous sommes retrouvés à une altitude énorme.@1 + +Surface Portal=Portail de surface + +There is a floating land of hills and forests up there, over the edges of which is a perilous drop all the way back down to sea level. We have not found how far these pristine lands extend. I have half a mind to retire there one day.=Il y a là un monde flottant remplis de collines et de forêts, sur les bords duquel se trouve une chute périlleuse jusqu'au niveau de la mer. Nous n'avons pas encore trouvé jusqu'où s'étendent ces terres vierges. J'ai à moitié envie de m'y retirer un jour. + + +### tools.lua ### + +Nether Axe= +Nether Ingot= +Nether Lump= +Nether Pickaxe= +Nether Shovel= +Nether Sword= diff --git a/locale/template.txt b/locale/template.txt index d594f08..0dfcf32 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -1,61 +1,98 @@ -# textdomain: nether - - - -### init.lua ### - -Construction requires 14 blocks of obsidian, which we found deep underground where water had solidified molten rock. The finished frame is four blocks wide, five blocks high, and stands vertically, like a doorway.@n@nThis opens to a truly hellish place, though for small mercies the air there is still breathable. There is an intriguing dimensional mismatch happening between this realm and ours, as after opening the second portal into it we observed that 10 strides taken in the Nether appear to be an equivalent of @1 in the natural world.@n@nThe 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.= - - -### init.lua ### -### nodes.lua ### - -Nether Portal= - -### nodes.lua ### - -Glowstone= -Inner Nether Stair= -Nether Brick= -Nether Brick Fence= -Nether Slab= -Nether Stair= -Netherrack= -Nethersand= -Outer Nether Stair= - -### portal_api.lua ### - -@n@nThe key to opening such a doorway is to strike the frame with a @1, at which point the very air inside begins to crackle and glow.= - -A definitive guide to Rifts and Portals= - -A guidebook for how to build portals to other realms. It can sometimes be found in dungeon chests, however a copy of this book is not needed as its contents are included in this Encyclopedia.= - -Book of Portals= -Building Portals= - -In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only @1 can I confirm as being more than merely stories.= - -In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only one can I confirm as being more than merely a story.= - -Portal wormhole= - -Portals to other realms can be opened by building a frame in the right shape with the right blocks, then using an item to activate it. A local copy of the guidebook to portals is published below.@n---@n@n= - -Refer: "Help" > "Basics" > "Building Portals"= -Untitled portal= -We know almost nothing about this portal= - -### portal_examples.lua ### - -Floatlands Portal= - -Requiring 16 blocks of tin and constructed in a circular fashion, a finished frame is seven blocks wide, seven blocks high, and stands vertically like a doorway.@n@nThese travel a distance along the ground, and even when constructed deep underground will link back up to the surface. They appear to favor a strange direction, with the exit portal linking back only for as long as the portal stays open — attempting to reopen a portal from the exit doorway leads to a new destination along this favored direction. It has stymied our ability to study the behavior of these portals because without constructing dual portals and keeping both open it's hard to step through more than one and still be able to return home.@n@nDue to such difficulties, we never learned what determines the direction and distance where the matching twin portal will appear, and I have lost my friend and protégé. In cavalier youth and with little more than a rucksack, Coudreau has decided to follow the chain as far as it goes, and has not been seen since. Coudreau believes it works in epicycles, but I am not convinced. Still, I cling to the hope that one day the portal will open and Coudreau will step out from whichever place leads to this one, perhaps with an epic tale to tell.= - -Requiring 21 blocks of ice, and constructed in the shape of a 3 × 3 platform with walls, or like a bowl. A finished platform is 2 blocks high, and 5 blocks wide at the widest in both directions.@n@nThis portal is different to the others, rather than acting akin to a doorway it appears to the eye more like a small pool of water which can be stepped into. Upon setting foot in the portal we found ourselves at a tremendous altitude.@1= - -Surface Portal= - -There is a floating land of hills and forests up there, over the edges of which is a perilous drop all the way back down to sea level. We have not found how far these pristine lands extend. I have half a mind to retire there one day.= - +# textdomain: nether + + + +### init.lua ### + +Construction requires 14 blocks of obsidian, which we found deep underground where water had solidified molten rock. The finished frame is four blocks wide, five blocks high, and stands vertically, like a doorway.@n@nThis opens to a truly hellish place, though for small mercies the air there is still breathable. There is an intriguing dimensional mismatch happening between this realm and ours, as after opening the second portal into it we observed that 10 strides taken in the Nether appear to be an equivalent of @1 in the natural world.@n@nThe 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.= + + +### init.lua ### +### nodes.lua ### + +Nether Portal= + +### nodes.lua ### + += +A finely finished block of solid Nether Basalt.= +A rough cut solid block of Nether Basalt.= +A thin crust of cooled lava with liquid lava beneath= +A vent in the earth emitting steam and gas= +Can be repurposed to provide puffs of smoke in a chimney= +Chiselled Basalt= + +Columns of dark basalt found only in magma oceans deep within the Nether.= + +Compressed Netherbrick= +Cracked Nether Brick= +Deep Glowstone= +Deep Netherrack= +Fumarolic Chimney= +Fumarolic Chimney Corner= +Fumarolic Chimney Slab= +Glowstone= +Hewn Basalt= +Inner Nether Stair= +Lava Crust= + +Lava crust is strong enough to walk on, but still hot enough to inflict burns.= + +Nether Basalt= +Nether Brick= +Nether Brick Fence= +Nether Slab= +Nether Stair= +Netherrack= +Netherrack from deep in the mantle= +Netherrack stair= +Nethersand= +Outer Nether Stair= +Portal= + +### portal_api.lua ### + +@n@nThe key to opening such a doorway is to strike the frame with a @1, at which point the very air inside begins to crackle and glow.= + +A definitive guide to Rifts and Portals= + +A guidebook for how to build portals to other realms. It can sometimes be found in dungeon chests, however a copy of this book is not needed as its contents are included in this Encyclopedia.= + +Book of Portals= +Building Portals= + +In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only @1 can I confirm as being more than merely stories.= + +In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only one can I confirm as being more than merely a story.= + +Mysterious forces prevented you from opening that portal. Please try another location= + +Portal wormhole= + +Portals to other realms can be opened by building a frame in the right shape with the right blocks, then using an item to activate it. A local copy of the guidebook to portals is published below.@n---@n@n= + +Refer: "Help" > "Basics" > "Building Portals"= +Untitled portal= +We know almost nothing about this portal= + +### portal_examples.lua ### + +Floatlands Portal= + +Requiring 16 blocks of tin and constructed in a circular fashion, a finished frame is seven blocks wide, seven blocks high, and stands vertically like a doorway.@n@nThese travel a distance along the ground, and even when constructed deep underground will link back up to the surface. They appear to favor a strange direction, with the exit portal linking back only for as long as the portal stays open — attempting to reopen a portal from the exit doorway leads to a new destination along this favored direction. It has stymied our ability to study the behavior of these portals because without constructing dual portals and keeping both open it's hard to step through more than one and still be able to return home.@n@nDue to such difficulties, we never learned what determines the direction and distance where the matching twin portal will appear, and I have lost my friend and protégé. In cavalier youth and with little more than a rucksack, Coudreau has decided to follow the chain as far as it goes, and has not been seen since. Coudreau believes it works in epicycles, but I am not convinced. Still, I cling to the hope that one day the portal will open and Coudreau will step out from whichever place leads to this one, perhaps with an epic tale to tell.= + +Requiring 21 blocks of ice, and constructed in the shape of a 3 × 3 platform with walls, or like a bowl. A finished platform is 2 blocks high, and 5 blocks wide at the widest in both directions.@n@nThis portal is different to the others, rather than acting akin to a doorway it appears to the eye more like a small pool of water which can be stepped into. Upon setting foot in the portal we found ourselves at a tremendous altitude.@1= + +Surface Portal= + +There is a floating land of hills and forests up there, over the edges of which is a perilous drop all the way back down to sea level. We have not found how far these pristine lands extend. I have half a mind to retire there one day.= + + +### tools.lua ### + +Nether Axe= +Nether Ingot= +Nether Lump= +Nether Pickaxe= +Nether Shovel= +Nether Sword= diff --git a/mapgen.lua b/mapgen.lua index abc145a..4b712be 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -198,7 +198,7 @@ minetest.register_ore({ minetest.register_ore({ ore_type = "scatter", - ore = "nether:lava_crust", -- crusted lava replaces of scattered glowstone in the mantle + ore = "nether:lava_crust", -- crusted lava replaces scattered glowstone in the mantle wherein = "nether:rack_deep", clust_scarcity = 16 * 16 * 16, clust_num_ores = 4, diff --git a/nodes.lua b/nodes.lua index 2af360e..dea7070 100644 --- a/nodes.lua +++ b/nodes.lua @@ -77,7 +77,8 @@ minetest.register_node("nether:rack", { -- Deep Netherrack, found in the mantle / central magma layers minetest.register_node("nether:rack_deep", { - description = S("Deep-Netherrack"), + description = S("Deep Netherrack"), + _doc_items_longdesc = S("Netherrack from deep in the mantle"), tiles = {"nether_rack_deep.png"}, is_ground_content = true, groups = {cracky = 3, level = 2}, @@ -106,7 +107,7 @@ minetest.register_node("nether:glowstone", { -- Deep glowstone, found in the mantle / central magma layers minetest.register_node("nether:glowstone_deep", { - description = S("Deep-Glowstone"), + description = S("Deep Glowstone"), tiles = {"nether_glowstone_deep.png"}, is_ground_content = true, light_source = 14, @@ -204,7 +205,8 @@ end -- obsidian that's available for other mods to use. -- It cannot be found in the regions of the nether where Nether portals link to, so requires a journey to obtain. minetest.register_node("nether:basalt", { - description = S("Blue Basalt"), + description = S("Nether Basalt"), + _doc_items_longdesc = S("Columns of dark basalt found only in magma oceans deep within the Nether."), tiles = { "nether_basalt.png", "nether_basalt.png", @@ -225,6 +227,7 @@ minetest.register_node("nether:basalt", { -- MT 5.0 world-align texture features. minetest.register_node("nether:basalt_hewn", { description = S("Hewn Basalt"), + _doc_items_longdesc = S("A rough cut solid block of Nether Basalt."), tiles = {{ name = "nether_basalt_hewn.png", align_style = "world", @@ -247,6 +250,7 @@ minetest.register_node("nether:basalt_hewn", { -- require the MT 5.0 world-align texture features. minetest.register_node("nether:basalt_chiselled", { description = S("Chiselled Basalt"), + _doc_items_longdesc = S("A finely finished block of solid Nether Basalt."), tiles = { "nether_basalt_chiselled_top.png", "nether_basalt_chiselled_top.png" .. "^[transformFY", @@ -467,7 +471,9 @@ end -- lava_crust nodes can only be used in the biomes-based mapgen, since they require -- the MT 5.0 world-align texture features. minetest.register_node("nether:lava_crust", { - description = "Lava crust", + description = S("Lava Crust"), + _doc_items_longdesc = S("A thin crust of cooled lava with liquid lava beneath"), + _doc_items_usagehelp = S("Lava crust is strong enough to walk on, but still hot enough to inflict burns."), tiles = { { name="nether_lava_crust_animated.png", @@ -677,7 +683,9 @@ end minetest.register_node("nether:fumarole", { - description="Fumarolic Chimney", + description=S("Fumarolic Chimney"), + _doc_items_longdesc = S("A vent in the earth emitting steam and gas"), + _doc_items_usagehelp = S("Can be repurposed to provide puffs of smoke in a chimney"), tiles = {"nether_rack.png"}, on_timer = fumarole_onTimer, after_place_node = function(pos, placer, itemstack, pointed_thing) @@ -701,7 +709,9 @@ minetest.register_node("nether:fumarole", { }) minetest.register_node("nether:fumarole_slab", { - description="Fumarolic Chimney Slab", + description=S("Fumarolic Chimney Slab"), + _doc_items_longdesc = S("A vent in the earth emitting steam and gas"), + _doc_items_usagehelp = S("Can be repurposed to provide puffs of smoke in a chimney"), tiles = {"nether_rack.png"}, is_ground_content = true, on_timer = fumarole_onTimer, @@ -726,7 +736,7 @@ minetest.register_node("nether:fumarole_slab", { }) minetest.register_node("nether:fumarole_corner", { - description="Fumarolic Chimney Corner", + description=S("Fumarolic Chimney Corner"), tiles = {"nether_rack.png"}, is_ground_content = true, groups = {cracky = 3, level = 2, fumarole=1}, From 4b508f8492f245d59762ad8997b029077428fe8a Mon Sep 17 00:00:00 2001 From: Treer Date: Fri, 15 Jan 2021 00:05:32 +1100 Subject: [PATCH 3/3] Update README.md --- README.md | 25 +++++++++++++++++++++---- mapgen.lua | 8 ++++---- mapgen_mantle.lua | 8 ++++---- portal_api.txt | 3 +++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dca4ca7..0b856af 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,27 @@ -Nether Mod for Minetest, with Portals API. +# Nether Mod for Minetest, with Portals API. + +Enables Nether portals to be built, opening a gateway between the surface +realm and one of lava and netherrack, with rumors of a passageway to a great +magma ocean. + +To view the options provided by this mod, see settingtypes.txt or +go to "Settings"->"All Settings"->"Mods"->"nether" in the game. + +A Nether portal is built as a rectangular vertical frame of obsidian, 4 blocks +wide and 5 blocks high. Once constructed, a Mese crystal fragment can be +right-click/used on the frame to activate it. + + +## Modders and game designers See portal_api.txt for how to create custom portals to your own realms. -See settingtypes.txt or go to "Settings"->"All Settings"->"Mods"->"nether" -in the game to view the options provided by this mod. - +This mod provides Nether basalts (natural, hewn, and chiseled) as nodes which +require a player to journey to the magma ocean to obtain, so these can be used +for gating progression through a game. For example, a portal to another realm +might need to be constructed from basalt, thus requiring a journey through +the nether first, or basalt might be a crafting ingredient required to reach +a particular branch of the tech-tree. ## License of source code: diff --git a/mapgen.lua b/mapgen.lua index 4b712be..c82a7db 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -161,7 +161,7 @@ minetest.register_node("nether:native_mapgen", {}) minetest.register_biome({ name = "nether_caverns", node_stone = "nether:native_mapgen", -- nether:native_mapgen is used here to prevent the native mapgen from placing ores and decorations. - node_filler = "nether:native_mapgen", -- The lua on_generate will transform nether:rack_native into nether:rack then decorate and add ores. + node_filler = "nether:native_mapgen", -- The lua on_generate will transform nether:native_mapgen into nether:rack then decorate and add ores. node_dungeon = "nether:brick", node_dungeon_alt = "nether:brick_cracked", node_dungeon_stair = "stairs:stair_nether_brick", @@ -525,7 +525,7 @@ local function on_generated(minp, maxp, seed) for y = y0, y1 do -- Y loop first to minimise tcave & lava-sea calculations - local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(y) + local sea_level, cavern_limit_distance = mapgen.find_nearest_lava_sealevel(y) -- function provided by mapgen_mantle.lua local above_lavasea = y > sea_level local below_lavasea = y < sea_level @@ -534,7 +534,7 @@ local function on_generated(minp, maxp, seed) local tmantle = CENTER_REGION_LIMIT + centerRegionLimit_adj -- cavern_noise_adj already contains central_region_limit_adj, so tmantle is only for comparisons when cavern_noise_adj hasn't been added to the noise value local cavern_noise_adj = CENTER_REGION_LIMIT * (cavern_limit_distance * cavern_limit_distance * cavern_limit_distance) - - centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj so subtract centerRegionLimit_adj instead of adding + centerRegionLimit_adj -- cavern_noise_adj gets added to noise value instead of added to the limit np_noise is compared against, so subtract centerRegionLimit_adj instead of adding for z = z0, z1 do local vi = area:index(x0, y, z) -- Initial voxelmanip index @@ -548,7 +548,7 @@ local function on_generated(minp, maxp, seed) if cave_noise > tcave then -- Prime region -- This was the only region in initial versions of the Nether mod. - -- It is the only region that portals from the surface will open into. + -- It is the only region which portals from the surface will open into. data[vi] = c_air contains_nether = true diff --git a/mapgen_mantle.lua b/mapgen_mantle.lua index 0add888..e453e19 100644 --- a/mapgen_mantle.lua +++ b/mapgen_mantle.lua @@ -286,7 +286,7 @@ function excavate_pathway(data, area, nether_pos, center_pos, minp, maxp) radiusLimit = math_min(radiusLimit, vector_min(vector.subtract(maxp, stopPos))) if radiusLimit < 4 then -- This is a logic check, ignore it. It could be commented out - -- 4 is (79 - 75), and shouldn't be possible if sampling-skip was 10 + -- 4 is (79 - 75), and values less than 4 shouldn't be possible if sampling-skip was 10 -- i.e. if sampling-skip was 10 then {5, 15, 25, 35, 45, 55, 65, 75} should be sampled from possible positions 0 to 79 debugf("Error: radiusLimit %s is smaller then half the sampling distance. min %s, max %s, start %s, stop %s", radiusLimit, minp, maxp, startPos, stopPos) end @@ -304,7 +304,7 @@ function excavate_pathway(data, area, nether_pos, center_pos, minp, maxp) local sizeAdj = 1 - (distFromMiddle * distFromMiddle * distFromMiddle) local radius = math_min(radiusLimit, math.random(50 - (25 * sizeAdj), 80 - (45 * sizeAdj)) / 10) - local radiusCubed = radius * radius + local radiusSquared = radius * radius local radiusCeil = math_floor(radius + 0.5) linedata[i].radius = radius -- Needed in third pass @@ -315,7 +315,7 @@ function excavate_pathway(data, area, nether_pos, center_pos, minp, maxp) local vi_z = vi + z * zstride for y = -radiusCeil, radiusCeil do local vi_zy = vi_z + y * ystride - local xSquaredLimit = radiusCubed - (z * z + y * y) + local xSquaredLimit = radiusSquared - (z * z + y * y) for x = -radiusCeil, radiusCeil do if x * x < xSquaredLimit then data[vi_zy + x] = c_air @@ -327,7 +327,7 @@ function excavate_pathway(data, area, nether_pos, center_pos, minp, maxp) end -- Third pass: decorate - -- Add glowstones to make tunnels to the mantle easyier to find + -- Add glowstones to make tunnels to the mantle easier to find -- https://i.imgur.com/sRA28x7.jpg for i = start_index, stop_index, 3 do if linedata[i].distFromEnds < 0.3 then diff --git a/portal_api.txt b/portal_api.txt index 74bfbb2..ecac500 100644 --- a/portal_api.txt +++ b/portal_api.txt @@ -22,6 +22,9 @@ one kind of portal with the same frame material — such as obsidian — provide the size of the PortalShape is distinct from any other type of portal that is using the same node for its frame, and portal sizes remain small. +The Nether provides three variants of Nether basalt to ensure there are +alternatives to obsidian for other mods to use as portalstones. + Realms ------