]> git.lizzy.rs Git - Crafter.git/blob - mods/nether/init.lua
dabf3699e5392889219c798b02d8dc0e5a7df443
[Crafter.git] / mods / nether / init.lua
1 local path = minetest.get_modpath("nether")
2 dofile(path.."/schem.lua")
3
4 minetest.register_biome({
5         name = "Nether",
6         node_top = "air",
7         depth_top = 0,
8         node_filler = "air",
9         depth_filler = 0,
10         node_riverbed = "air",
11         depth_riverbed= 0,
12         node_stone = "air",
13         node_water = "air",
14         node_dungeon = "air",
15         node_dungeon_alt = "air",
16         node_dungeon_stair = "air",
17         vertical_blend = 0,
18         y_max = -10000,
19         y_min = -20000,
20         heat_point = -100,
21         humidity_point = -100,
22 })
23
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
31 })
32
33
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,
40     light_source = 7,
41 })
42
43
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)
53     end,
54     --light_source = 7,
55 })
56
57 --this is from https://github.com/paramat/lvm_example/blob/master/init.lua
58 --hi paramat :D
59
60 -- Set the 3D noise parameters for the terrain.
61 local perlin= minetest.get_mapgen_params()
62 local np_terrain = {
63         offset = 0,
64         scale = 1,
65         spread = {x = 384, y = 192, z = 384},
66         seed = 5900033, --perlin.seed
67         octaves = 5,
68         persist = 0.63,
69         lacunarity = 2.0,
70         --flags = ""
71 }
72
73
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.
77
78 --minetest.set_mapgen_params({mgname = "singlenode", flags = "nolight"})
79
80
81 -- Get the content IDs for the nodes used.
82
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")
87
88
89 -- Initialize noise object to nil. It will be created once only during the
90 -- generation of the first mapchunk, to minimise memory use.
91
92 local nobj_terrain = nil
93
94
95 -- Localise noise buffer table outside the loop, to be re-used for all
96 -- mapchunks, therefore minimising memory use.
97
98 local nvals_terrain = {}
99
100
101 -- Localise data buffer table outside the loop, to be re-used for all
102 -- mapchunks, therefore minimising memory use.
103
104 local data = {}
105
106
107 -- On generated function.
108
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
114                 return
115         end
116         -- Start time of mapchunk generation.
117         --local t0 = os.clock()
118         
119         -- Noise stuff.
120
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)
132
133         -- Voxelmanip stuff.
134
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.
142         vm:get_data(data)
143
144         -- Generation loop.
145
146         -- Noise index for the flat array of noise values.
147         local ni = 1
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
152         -- rows.
153         -- rows.
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
170                         
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
178                                 data[vi] = c_bedrock
179                         --elseif y <= 1 then
180                         --      data[vi] = c_water
181                         elseif y > -15000 then
182                                 data[vi] = c_air
183                         else
184                                 data[vi] = c_lava
185                         end
186
187                         -- Increment noise index.
188                         ni = ni + 1
189                         -- Increment voxelmanip index along x row.
190                         -- The voxelmanip index increases by 1 when
191                         -- moving by 1 node in the +x direction.
192                         vi = vi + 1
193                 end
194         end
195         end
196
197         -- After processing, write content ID data back to the voxelmanip.
198         vm:set_data(data)
199         -- Calculate lighting for what has been created.
200         --vm:calc_lighting()
201         
202         vm:set_lighting({day=7,night=7}, minp, maxp)
203         
204         -- Write what has been created to the world.
205         vm:write_to_map()
206         -- Liquid nodes were placed so set them flowing.
207         --vm:update_liquids()
208
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")
212 end)
213
214
215 minetest.register_node("nether:portal", {
216         description = "Nether Portal",
217
218         tiles = {
219                 {
220                         name = "nether_portal.png",
221                         animation = {
222                                 type = "vertical_frames",
223                                 aspect_w = 16,
224                                 aspect_h = 16,
225                                 length = 0.5,
226                         },
227                 },
228                 {
229                         name = "nether_portal.png",
230                         animation = {
231                                 type = "vertical_frames",
232                                 aspect_w = 16,
233                                 aspect_h = 16,
234                                 length = 0.5,
235                         },
236                 },
237         },
238         drawtype = "nodebox",
239         paramtype = "light",
240         --paramtype2 = "facedir",
241         sunlight_propagates = true,
242         use_texture_alpha = false,
243         walkable = false,
244         diggable = false,
245         pointable = false,
246         buildable_to = false,
247         is_ground_content = false,
248         drop = "",
249         light_source = 7,
250         --post_effect_color = {a = 180, r = 51, g = 7, b = 89},
251         --alpha = 192,
252         node_box = {
253         type = "connected",
254                 -- connect_top =
255                 -- connect_bottom =
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},
260         },
261         connects_to = {"nether:portal","nether:obsidian"},
262         groups = {unbreakable=1},
263         --on_destruct = destroy_portal,
264 })
265
266 --branch out from center
267 local n_index = {}
268 local portal_failure = false
269 local x_failed = false
270
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
274         if not origin then
275                 origin = pos
276                 portal_failure = false
277         end
278         if not axis then
279                 axis = "x"
280         end
281                 
282         --2d virtual memory map creation (x axis)
283         if axis == "x" then
284                 for x = -1,1 do
285                 for y = -1,1 do
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))
289                                 
290                                 local execute_collection = true
291                                 
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
295                                         end
296                                 end     
297                                 
298                                 if execute_collection == true then
299                                         --print(minetest.get_node(i).name)
300                                         --index air
301                                         if minetest.get_node(i).name == "air" then
302                                                 
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")
312                                                 else
313                                                         --print("try z")
314                                                         x_failed = true
315                                                         n_index = {}
316                                                         create_nether_portal(origin,origin,"z")
317                                                 end
318                                         elseif minetest.get_node(i).name ~= "nether:obsidian" then
319                                                 x_failed = true
320                                                 n_index = {}
321                                                 create_nether_portal(origin,origin,"z")
322                                         end
323                                 end
324                         end
325                 end
326                 end
327         --2d virtual memory map creation (z axis)
328         elseif axis == "z" then
329                 for z = -1,1 do
330                 for y = -1,1 do
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))
334                                 
335                                 local execute_collection = true
336                                 
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
340                                         end
341                                 end     
342                                 
343                                 if execute_collection == true then
344                                         --print(minetest.get_node(i).name)
345                                         --index air
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")
356                                                 else
357                                                         --print("portal failed")
358                                                         portal_failure = true
359                                                         n_index = {}
360                                                         --print("try z")
361                                                 end
362                                         elseif minetest.get_node(i).name ~= "nether:obsidian" then
363                                                 --print("portal failed")
364                                                 portal_failure = true
365                                                 n_index = {}
366                                         end
367                                 end
368                         end
369                 end
370                 end
371         end
372 end
373
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"})
380                                 
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"})
385                         
386                         if platform and next(platform) then
387                                 --print("setting the platform")
388                                 local platform_location = platform[math.random(1,table.getn(platform))]
389                                 
390                                 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
391                         else
392                                 --print("generate a portal within netherrack")
393                                 minetest.place_schematic(nether_origin_pos, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
394                         end
395                 else
396                         --print("portal exists, utilizing")
397                 end
398                 nether_origin_pos = nil
399         end
400 end
401
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"})
405                                 
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"})
410                         
411                         if platform and next(platform) then
412                                 --print("setting the platform")
413                                 local platform_location = platform[math.random(1,table.getn(platform))]
414                                 
415                                 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
416                         else
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")
419                         end
420                 else
421                         --print("portal exists, utilizing")
422                 end
423                 nether_origin_pos = nil
424         end
425 end
426
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
432                 
433                 local min = vector.subtract(nether_origin_pos,30)
434                 local max = vector.add(nether_origin_pos,30)
435                 
436                 --force load the area
437                 minetest.emerge_area(min, max, spawn_portal_into_nether_callback)
438         else
439                 --center the location to the water height
440                 pos.y = 0--+math.random(-30,30) 
441                 nether_origin_pos = pos
442                 
443                 local min = vector.subtract(nether_origin_pos,30)
444                 local max = vector.add(nether_origin_pos,30)
445                 
446                 --force load the area
447                 minetest.emerge_area(min, max, spawn_portal_into_overworld_callback)
448         end
449 end
450
451
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))
463                                 end
464                                 table.insert(sorted_table, vector.new(x,y,z))
465                         end
466                 end
467         end
468         minetest.bulk_set_node(sorted_table, {name="nether:portal"})
469 end
470
471 -------------------------------------------------------------------------------
472
473 local destroy_n_index = {}
474 local destroy_portal_failure = false
475 local destroy_x_failed = false
476
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
480         if not origin then
481                 origin = pos
482         end             
483         --3d virtual memory map creation (x axis)
484         for x = -1,1 do
485         for z = -1,1 do
486         for y = -1,1 do
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))
490                         
491                         local execute_collection = true
492                         
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
496                                 end
497                         end     
498                         
499                         if execute_collection == true then
500                                 --print(minetest.get_node(i).name)
501                                 --index air
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")
512                                         end
513                                 end
514                         end
515                 end
516         end
517         end
518         end
519 end
520
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))
528                         end
529                 end
530         end
531         minetest.bulk_set_node(destroy_sorted_table, {name="air"})
532 end
533
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
541         end
542         if x_failed == true then
543                 x_failed = false
544         end
545         if portal_failure == true then
546                 portal_failure = false
547         end
548         --clear the index to avoid cpu looping wasting processing power
549         n_index = {}
550         
551         
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)
557         end
558         --clear the index to avoid cpu looping wasting processing power
559         destroy_n_index = {}
560 end)