1 local path = minetest.get_modpath("nether")
2 dofile(path.."/schem.lua")
4 minetest.register_biome({
10 node_riverbed = "air",
15 node_dungeon_alt = "air",
16 node_dungeon_stair = "air",
21 humidity_point = -100,
24 minetest.register_node("nether:bedrock", {
25 description = "Bedrock",
26 tiles = {"bedrock.png"},
27 groups = {unbreakable = 1, pathable = 1},
28 sounds = main.stoneSound(),
29 is_ground_content = false,
30 --light_source = 14, --debugging
34 minetest.register_node("nether:netherrack", {
35 description = "Netherrack",
36 tiles = {"netherrack.png"},
37 groups = {stone = 1, pathable = 1},
38 sounds = main.stoneSound(),
39 is_ground_content = false,
44 minetest.register_node("nether:obsidian", {
45 description = "Obsidian",
46 tiles = {"obsidian.png"},
47 --groups = {stone = 5, pathable = 1},
48 groups = {stone = 1, pathable = 1}, --leave this here for debug
49 sounds = main.stoneSound(),
50 is_ground_content = false,
51 after_destruct = function(pos, oldnode)
52 destroy_nether_portal(pos)
57 --this is from https://github.com/paramat/lvm_example/blob/master/init.lua
60 -- Set the 3D noise parameters for the terrain.
61 local perlin= minetest.get_mapgen_params()
65 spread = {x = 384, y = 192, z = 384},
66 seed = 5900033, --perlin.seed
74 -- Set singlenode mapgen (air nodes only).
75 -- Disable the engine lighting calculation since that will be done for a
76 -- mapchunk of air nodes and will be incorrect after we place nodes.
78 --minetest.set_mapgen_params({mgname = "singlenode", flags = "nolight"})
81 -- Get the content IDs for the nodes used.
83 local c_sandstone = minetest.get_content_id("nether:netherrack")
84 local c_bedrock = minetest.get_content_id("nether:bedrock")
85 local c_air = minetest.get_content_id("air")
86 local c_lava = minetest.get_content_id("main:lava")
89 -- Initialize noise object to nil. It will be created once only during the
90 -- generation of the first mapchunk, to minimise memory use.
92 local nobj_terrain = nil
95 -- Localise noise buffer table outside the loop, to be re-used for all
96 -- mapchunks, therefore minimising memory use.
98 local nvals_terrain = {}
101 -- Localise data buffer table outside the loop, to be re-used for all
102 -- mapchunks, therefore minimising memory use.
107 -- On generated function.
109 -- 'minp' and 'maxp' are the minimum and maximum positions of the mapchunk that
110 -- define the 3D volume.
111 minetest.register_on_generated(function(minp, maxp, seed)
112 --nether starts at -10033 y
113 if maxp.y > -10033 then
116 -- Start time of mapchunk generation.
117 --local t0 = os.clock()
121 -- Side length of mapchunk.
122 local sidelen = maxp.x - minp.x + 1
123 -- Required dimensions of the 3D noise perlin map.
124 local permapdims3d = {x = sidelen, y = sidelen, z = sidelen}
125 -- Create the perlin map noise object once only, during the generation of
126 -- the first mapchunk when 'nobj_terrain' is 'nil'.
127 nobj_terrain = minetest.get_perlin_map(np_terrain, permapdims3d) --nobj_terrain or
128 -- Create a flat array of noise values from the perlin map, with the
129 -- minimum point being 'minp'.
130 -- Set the buffer parameter to use and reuse 'nvals_terrain' for this.
131 nobj_terrain:get3dMap_flat(minp, nvals_terrain)
135 -- Load the voxelmanip with the result of engine mapgen. Since 'singlenode'
136 -- mapgen is used this will be a mapchunk of air nodes.
137 local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
138 -- 'area' is used later to get the voxelmanip indexes for positions.
139 local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
140 -- Get the content ID data from the voxelmanip in the form of a flat array.
141 -- Set the buffer parameter to use and reuse 'data' for this.
146 -- Noise index for the flat array of noise values.
148 -- Process the content IDs in 'data'.
149 -- The most useful order is a ZYX loop because:
150 -- 1. This matches the order of the 3D noise flat array.
151 -- 2. This allows a simple +1 incrementing of the voxelmanip index along x
154 for z = minp.z, maxp.z do
155 for y = minp.y, maxp.y do
156 -- Voxelmanip index for the flat array of content IDs.
157 -- Initialise to first node in this x row.
158 local vi = area:index(minp.x, y, z)
159 for x = minp.x, maxp.x do
160 -- Consider a 'solidness' value for each node,
161 -- let's call it 'density', where
162 -- density = density noise + density gradient.
163 local density_noise = nvals_terrain[ni]
164 -- Density gradient is a value that is 0 at water level (y = 1)
165 -- and falls in value with increasing y. This is necessary to
166 -- create a 'world surface' with only solid nodes deep underground
167 -- and only air high above water level.
168 -- Here '128' determines the typical maximum height of the terrain.
169 local density_gradient = (1 - y) / 128
171 --print(density_noise, density_gradient)
172 -- Place solid nodes when 'density' > 0.
173 --if density_noise + density_gradient > 0 then
174 if density_noise > 0 and y ~= -10033 then
175 data[vi] = c_sandstone
176 -- Otherwise if at or below water level place water.
177 elseif y == -10033 then
180 -- data[vi] = c_water
181 elseif y > -15000 then
187 -- Increment noise index.
189 -- Increment voxelmanip index along x row.
190 -- The voxelmanip index increases by 1 when
191 -- moving by 1 node in the +x direction.
197 -- After processing, write content ID data back to the voxelmanip.
199 -- Calculate lighting for what has been created.
202 vm:set_lighting({day=7,night=7}, minp, maxp)
204 -- Write what has been created to the world.
206 -- Liquid nodes were placed so set them flowing.
207 --vm:update_liquids()
209 -- Print generation time of this mapchunk.
210 --local chugent = math.ceil((os.clock() - t0) * 1000)
211 --print ("[lvm_example] Mapchunk generation time " .. chugent .. " ms")
215 minetest.register_node("nether:portal", {
216 description = "Nether Portal",
220 name = "nether_portal.png",
222 type = "vertical_frames",
229 name = "nether_portal.png",
231 type = "vertical_frames",
238 drawtype = "nodebox",
240 --paramtype2 = "facedir",
241 sunlight_propagates = true,
242 use_texture_alpha = false,
246 buildable_to = false,
247 is_ground_content = false,
250 --post_effect_color = {a = 180, r = 51, g = 7, b = 89},
256 connect_front = {-1/16, -1/2, -1/2, 1/16, 1/2, 0 },
257 connect_left = {-1/2, -1/2, -1/16, 0, 1/2, 1/16},
258 connect_back = {-1/16, -1/2, 0, 1/16, 1/2, 1/2 },
259 connect_right = { 0, -1/2, -1/16, 1/2, 1/2, 1/16},
261 connects_to = {"nether:portal","nether:obsidian"},
262 groups = {unbreakable=1},
263 --on_destruct = destroy_portal,
266 --branch out from center
268 local portal_failure = false
269 local x_failed = false
271 --this can be used globally to create nether portals from obsidian
272 function create_nether_portal(pos,origin,axis)
273 --create the origin node for stored memory
276 portal_failure = false
282 --2d virtual memory map creation (x axis)
286 --index only direct neighbors
287 if x_failed == false and (math.abs(x)+math.abs(y) == 1) then
288 local i = vector.add(pos,vector.new(x,y,0))
290 local execute_collection = true
292 if n_index[i.x] and n_index[i.x][i.y] then
293 if n_index[i.x][i.y][i.z] then
294 execute_collection = false
298 if execute_collection == true then
299 --print(minetest.get_node(i).name)
301 if minetest.get_node(i).name == "air" then
303 if vector.distance(i,origin) < 50 then
304 --add data to both maps
305 if not n_index[i.x] then n_index[i.x] = {} end
306 if not n_index[i.x][i.y] then n_index[i.x][i.y] = {} end
307 n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}
308 --the data to the 3d array must be written to memory before this is executed
309 --or a stack overflow occurs!!!
310 --pass down info for activators
311 create_nether_portal(i,origin,"x")
316 create_nether_portal(origin,origin,"z")
318 elseif minetest.get_node(i).name ~= "nether:obsidian" then
321 create_nether_portal(origin,origin,"z")
327 --2d virtual memory map creation (z axis)
328 elseif axis == "z" then
331 --index only direct neighbors
332 if x_failed == true and portal_failure == false and (math.abs(z)+math.abs(y) == 1) then
333 local i = vector.add(pos,vector.new(0,y,z))
335 local execute_collection = true
337 if n_index[i.x] and n_index[i.x][i.y] then
338 if n_index[i.x][i.y][i.z] then
339 execute_collection = false
343 if execute_collection == true then
344 --print(minetest.get_node(i).name)
346 if minetest.get_node(i).name == "air" then
347 if vector.distance(i,origin) < 50 then
348 --add data to both maps
349 if not n_index[i.x] then n_index[i.x] = {} end
350 if not n_index[i.x][i.y] then n_index[i.x][i.y] = {} end
351 n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}
352 --the data to the 3d array must be written to memory before this is executed
353 --or a stack overflow occurs!!!
354 --pass down info for activators
355 create_nether_portal(i,origin,"z")
357 --print("portal failed")
358 portal_failure = true
362 elseif minetest.get_node(i).name ~= "nether:obsidian" then
363 --print("portal failed")
364 portal_failure = true
374 --creates a nether portal in the nether
375 --this essentially makes it so you have to move 30 away from one portal to another otherwise it will travel to an existing portal
376 local nether_origin_pos = nil
377 local function spawn_portal_into_nether_callback(blockpos, action, calls_remaining, param)
378 if calls_remaining == 0 then
379 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
381 if not portal_exists then
382 local min = vector.subtract(nether_origin_pos,30)
383 local max = vector.add(nether_origin_pos,30)
384 local platform = minetest.find_nodes_in_area_under_air(min, max, {"nether:netherrack","main:lava"})
386 if platform and next(platform) then
387 --print("setting the platform")
388 local platform_location = platform[math.random(1,table.getn(platform))]
390 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
392 --print("generate a portal within netherrack")
393 minetest.place_schematic(nether_origin_pos, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
396 --print("portal exists, utilizing")
398 nether_origin_pos = nil
402 local function spawn_portal_into_overworld_callback(blockpos, action, calls_remaining, param)
403 if calls_remaining == 0 then
404 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
406 if not portal_exists then
407 local min = vector.subtract(nether_origin_pos,30)
408 local max = vector.add(nether_origin_pos,30)
409 local platform = minetest.find_nodes_in_area_under_air(min, max, {"main:stone","main:water","main:grass","main:sand","main:dirt"})
411 if platform and next(platform) then
412 --print("setting the platform")
413 local platform_location = platform[math.random(1,table.getn(platform))]
415 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
417 --print("generate a portal within overworld stone")
418 minetest.place_schematic(nether_origin_pos, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
421 --print("portal exists, utilizing")
423 nether_origin_pos = nil
427 local function generate_nether_portal_in_nether(pos)
428 if pos.y > -10033 then
429 --center the location to the lava height
430 pos.y = -15000--+math.random(-30,30)
431 nether_origin_pos = pos
433 local min = vector.subtract(nether_origin_pos,30)
434 local max = vector.add(nether_origin_pos,30)
436 --force load the area
437 minetest.emerge_area(min, max, spawn_portal_into_nether_callback)
439 --center the location to the water height
440 pos.y = 0--+math.random(-30,30)
441 nether_origin_pos = pos
443 local min = vector.subtract(nether_origin_pos,30)
444 local max = vector.add(nether_origin_pos,30)
446 --force load the area
447 minetest.emerge_area(min, max, spawn_portal_into_overworld_callback)
452 --modify the map with the collected data
453 local function portal_modify_map(n_copy)
454 local sorted_table = {}
455 local created_portal = false
456 for x,datax in pairs(n_copy) do
457 for y,datay in pairs(datax) do
458 for z,index in pairs(datay) do
459 --try to create a return side nether portal
460 if created_portal == false then
461 created_portal = true
462 generate_nether_portal_in_nether(vector.new(x,y,z))
464 table.insert(sorted_table, vector.new(x,y,z))
468 minetest.bulk_set_node(sorted_table, {name="nether:portal"})
471 -------------------------------------------------------------------------------
473 local destroy_n_index = {}
474 local destroy_portal_failure = false
475 local destroy_x_failed = false
477 --this can be used globally to create nether portals from obsidian
478 function destroy_nether_portal(pos,origin,axis)
479 --create the origin node for stored memory
483 --3d virtual memory map creation (x axis)
487 --index only direct neighbors
488 if (math.abs(x)+math.abs(z)+math.abs(y) == 1) then
489 local i = vector.add(pos,vector.new(x,y,z))
491 local execute_collection = true
493 if destroy_n_index[i.x] and destroy_n_index[i.x][i.y] then
494 if destroy_n_index[i.x][i.y][i.z] then
495 execute_collection = false
499 if execute_collection == true then
500 --print(minetest.get_node(i).name)
502 if minetest.get_node(i).name == "nether:portal" then
503 if vector.distance(i,origin) < 50 then
504 --add data to both maps
505 if not destroy_n_index[i.x] then destroy_n_index[i.x] = {} end
506 if not destroy_n_index[i.x][i.y] then destroy_n_index[i.x][i.y] = {} end
507 destroy_n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}
508 --the data to the 3d array must be written to memory before this is executed
509 --or a stack overflow occurs!!!
510 --pass down info for activators
511 destroy_nether_portal(i,origin,"z")
521 --modify the map with the collected data
522 local function destroy_portal_modify_map(destroy_n_copy)
523 local destroy_sorted_table = {}
524 for x,datax in pairs(destroy_n_copy) do
525 for y,datay in pairs(datax) do
526 for z,index in pairs(datay) do
527 table.insert(destroy_sorted_table, vector.new(x,y,z))
531 minetest.bulk_set_node(destroy_sorted_table, {name="air"})
534 minetest.register_globalstep(function(dtime)
535 --if indexes exist then calculate redstone
536 if n_index and next(n_index) and portal_failure == false then
537 --create the old version to help with deactivation calculation
538 local n_copy = table.copy(n_index)
539 portal_modify_map(n_copy)
540 portal_failure = false
542 if x_failed == true then
545 if portal_failure == true then
546 portal_failure = false
548 --clear the index to avoid cpu looping wasting processing power
552 --if indexes exist then calculate redstone
553 if destroy_n_index and next(destroy_n_index) and destroy_portal_failure == false then
554 --create the old version to help with deactivation calculation
555 local destroy_n_copy = table.copy(destroy_n_index)
556 destroy_portal_modify_map(destroy_n_copy)
558 --clear the index to avoid cpu looping wasting processing power