]> git.lizzy.rs Git - Crafter.git/blob - mods/nether/init.lua
Make glass easier to break and netherrack ultra easy to break
[Crafter.git] / mods / nether / init.lua
1 local nether_channel = minetest.mod_channel_join("nether_teleporters")
2
3 local path = minetest.get_modpath("nether")
4 dofile(path.."/schem.lua")
5
6 minetest.register_biome({
7         name = "Nether",
8         node_top = "air",
9         depth_top = 0,
10         node_filler = "air",
11         depth_filler = 0,
12         node_riverbed = "air",
13         depth_riverbed= 0,
14         node_stone = "air",
15         node_water = "air",
16         node_dungeon = "air",
17         node_dungeon_alt = "air",
18         node_dungeon_stair = "air",
19         vertical_blend = 0,
20         y_max = -10000,
21         y_min = -20000,
22         heat_point = -100,
23         humidity_point = -100,
24 })
25
26 minetest.register_node("nether:bedrock", {
27     description = "Bedrock",
28     tiles = {"bedrock.png"},
29     groups = {unbreakable = 1, pathable = 1},
30     sounds = main.stoneSound(),
31     is_ground_content = false,
32     --light_source = 14, --debugging
33 })
34
35
36 minetest.register_node("nether:netherrack", {
37     description = "Netherrack",
38     tiles = {"netherrack.png"},
39     groups = {netherrack = 1, pathable = 1},
40     sounds = main.stoneSound(),
41     is_ground_content = false,
42     light_source = 7,
43     drop = {
44                         max_items = 1,
45                         items= {
46                                 {
47                                         rarity = 0,
48                                         tools = {"main:woodpick","main:stonepick","main:ironpick","main:goldpick","main:diamondpick"},
49                                         items = {"nether:netherrack"},
50                                 },
51                                 },
52                         },
53 })
54
55
56 minetest.register_node("nether:obsidian", {
57     description = "Obsidian",
58     tiles = {"obsidian.png"},
59     groups = {stone = 5, pathable = 1},
60     --groups = {stone = 1, pathable = 1}, --leave this here for debug
61     sounds = main.stoneSound(),
62     is_ground_content = false,
63     after_destruct = function(pos, oldnode)
64                 destroy_nether_portal(pos)
65     end,
66     --light_source = 7,
67 })
68
69 --this is from https://github.com/paramat/lvm_example/blob/master/init.lua
70 --hi paramat :D
71
72 -- Set the 3D noise parameters for the terrain.
73 local perlin= minetest.get_mapgen_params()
74 local np_terrain = {
75         offset = 0,
76         scale = 1,
77         spread = {x = 384, y = 192, z = 384},
78         seed = 5900033, --perlin.seed
79         octaves = 5,
80         persist = 0.63,
81         lacunarity = 2.0,
82         --flags = ""
83 }
84
85
86 -- Set singlenode mapgen (air nodes only).
87 -- Disable the engine lighting calculation since that will be done for a
88 -- mapchunk of air nodes and will be incorrect after we place nodes.
89
90 --minetest.set_mapgen_params({mgname = "singlenode", flags = "nolight"})
91
92
93 -- Get the content IDs for the nodes used.
94
95 local c_sandstone = minetest.get_content_id("nether:netherrack")
96 local c_bedrock = minetest.get_content_id("nether:bedrock")
97 local c_air = minetest.get_content_id("air")
98 local c_lava = minetest.get_content_id("main:lava")
99
100
101 -- Initialize noise object to nil. It will be created once only during the
102 -- generation of the first mapchunk, to minimise memory use.
103
104 local nobj_terrain = nil
105
106
107 -- Localise noise buffer table outside the loop, to be re-used for all
108 -- mapchunks, therefore minimising memory use.
109
110 local nvals_terrain = {}
111
112
113 -- Localise data buffer table outside the loop, to be re-used for all
114 -- mapchunks, therefore minimising memory use.
115
116 local data = {}
117
118
119 -- On generated function.
120
121 -- 'minp' and 'maxp' are the minimum and maximum positions of the mapchunk that
122 -- define the 3D volume.
123 minetest.register_on_generated(function(minp, maxp, seed)
124         --nether starts at -10033 y
125         if maxp.y > -10033 then
126                 return
127         end
128         -- Start time of mapchunk generation.
129         --local t0 = os.clock()
130         
131         -- Noise stuff.
132
133         -- Side length of mapchunk.
134         local sidelen = maxp.x - minp.x + 1
135         -- Required dimensions of the 3D noise perlin map.
136         local permapdims3d = {x = sidelen, y = sidelen, z = sidelen}
137         -- Create the perlin map noise object once only, during the generation of
138         -- the first mapchunk when 'nobj_terrain' is 'nil'.
139         nobj_terrain = minetest.get_perlin_map(np_terrain, permapdims3d) --nobj_terrain or 
140         -- Create a flat array of noise values from the perlin map, with the
141         -- minimum point being 'minp'.
142         -- Set the buffer parameter to use and reuse 'nvals_terrain' for this.
143         nobj_terrain:get3dMap_flat(minp, nvals_terrain)
144
145         -- Voxelmanip stuff.
146
147         -- Load the voxelmanip with the result of engine mapgen. Since 'singlenode'
148         -- mapgen is used this will be a mapchunk of air nodes.
149         local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
150         -- 'area' is used later to get the voxelmanip indexes for positions.
151         local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
152         -- Get the content ID data from the voxelmanip in the form of a flat array.
153         -- Set the buffer parameter to use and reuse 'data' for this.
154         vm:get_data(data)
155
156         -- Generation loop.
157
158         -- Noise index for the flat array of noise values.
159         local ni = 1
160         -- Process the content IDs in 'data'.
161         -- The most useful order is a ZYX loop because:
162         -- 1. This matches the order of the 3D noise flat array.
163         -- 2. This allows a simple +1 incrementing of the voxelmanip index along x
164         -- rows.
165         -- rows.
166         for z = minp.z, maxp.z do
167         for y = minp.y, maxp.y do
168                 -- Voxelmanip index for the flat array of content IDs.
169                 -- Initialise to first node in this x row.
170                 local vi = area:index(minp.x, y, z)
171                 for x = minp.x, maxp.x do
172                         -- Consider a 'solidness' value for each node,
173                         -- let's call it 'density', where
174                         -- density = density noise + density gradient.
175                         local density_noise = nvals_terrain[ni]
176                         -- Density gradient is a value that is 0 at water level (y = 1)
177                         -- and falls in value with increasing y. This is necessary to
178                         -- create a 'world surface' with only solid nodes deep underground
179                         -- and only air high above water level.
180                         -- Here '128' determines the typical maximum height of the terrain.
181                         local density_gradient = (1 - y) / 128
182                         
183                         --print(density_noise, density_gradient)
184                         -- Place solid nodes when 'density' > 0.
185                         --if density_noise + density_gradient > 0 then
186                         if density_noise > 0  and y ~= -10033 then
187                                 data[vi] = c_sandstone
188                         -- Otherwise if at or below water level place water.
189                         elseif y == -10033 then
190                                 data[vi] = c_bedrock
191                         --elseif y <= 1 then
192                         --      data[vi] = c_water
193                         elseif y > -15000 then
194                                 data[vi] = c_air
195                         else
196                                 data[vi] = c_lava
197                         end
198
199                         -- Increment noise index.
200                         ni = ni + 1
201                         -- Increment voxelmanip index along x row.
202                         -- The voxelmanip index increases by 1 when
203                         -- moving by 1 node in the +x direction.
204                         vi = vi + 1
205                 end
206         end
207         end
208
209         -- After processing, write content ID data back to the voxelmanip.
210         vm:set_data(data)
211         -- Calculate lighting for what has been created.
212         --vm:calc_lighting()
213         
214         vm:set_lighting({day=7,night=7}, minp, maxp)
215         
216         -- Write what has been created to the world.
217         vm:write_to_map()
218         -- Liquid nodes were placed so set them flowing.
219         --vm:update_liquids()
220
221         -- Print generation time of this mapchunk.
222         --local chugent = math.ceil((os.clock() - t0) * 1000)
223         --print ("[lvm_example] Mapchunk generation time " .. chugent .. " ms")
224 end)
225
226
227 minetest.register_node("nether:portal", {
228         description = "Nether Portal",
229
230         tiles = {
231                 {
232                         name = "nether_portal.png",
233                         backface_culling = true,
234                         animation = {
235                                 type = "vertical_frames",
236                                 aspect_w = 16,
237                                 aspect_h = 16,
238                                 length = 0.5,
239                         },
240                 },
241                 {
242                         name = "nether_portal.png",
243                         backface_culling = true,
244                         animation = {
245                                 type = "vertical_frames",
246                                 aspect_w = 16,
247                                 aspect_h = 16,
248                                 length = 0.5,
249                         },
250                 },
251         },
252         drawtype = "nodebox",
253         paramtype = "light",
254         --paramtype2 = "facedir",
255         sunlight_propagates = true,
256         use_texture_alpha = false,
257         walkable = false,
258         diggable = false,
259         pointable = false,
260         buildable_to = false,
261         is_ground_content = false,
262         drop = "",
263         light_source = 7,
264         --post_effect_color = {a = 180, r = 51, g = 7, b = 89},
265         alpha = 140,
266         node_box = {
267         type = "connected",
268                 -- connect_top =
269                 -- connect_bottom =
270                 connect_front = {0,  -1/2, -1/2,   0,  1/2, 0 },
271                 connect_left =  {-1/2,   -1/2, 0, 0,   1/2,  0},
272                 connect_back =  {0,  -1/2,  0,   0,  1/2,  1/2 },
273                 connect_right = { 0,   -1/2, 0,  1/2,   1/2,  0},
274         },
275         connects_to = {"nether:portal","nether:obsidian"},
276         groups = {unbreakable=1},
277         --on_destruct = destroy_portal,
278 })
279
280 --branch out from center
281 local n_index = {}
282 local portal_failure = false
283 local x_failed = false
284
285 --this can be used globally to create nether portals from obsidian
286 function create_nether_portal(pos,origin,axis)
287         --create the origin node for stored memory
288         if not origin then
289                 origin = pos
290                 portal_failure = false
291         end
292         if not axis then
293                 axis = "x"
294         end
295                 
296         --2d virtual memory map creation (x axis)
297         if axis == "x" then
298                 for x = -1,1 do
299                 for y = -1,1 do
300                         --index only direct neighbors
301                         if x_failed == false and (math.abs(x)+math.abs(y) == 1) then
302                                 local i = vector.add(pos,vector.new(x,y,0))
303                                 
304                                 local execute_collection = true
305                                 
306                                 if n_index[i.x] and n_index[i.x][i.y] then
307                                         if n_index[i.x][i.y][i.z] then
308                                                 execute_collection = false
309                                         end
310                                 end     
311                                 
312                                 if execute_collection == true then
313                                         --print(minetest.get_node(i).name)
314                                         --index air
315                                         if minetest.get_node(i).name == "air" then
316                                                 
317                                                 if vector.distance(i,origin) < 50 then
318                                                         --add data to both maps
319                                                         if not n_index[i.x] then n_index[i.x] = {} end
320                                                         if not n_index[i.x][i.y] then n_index[i.x][i.y] = {} end
321                                                         n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}             
322                                                         --the data to the 3d array must be written to memory before this is executed
323                                                         --or a stack overflow occurs!!!
324                                                         --pass down info for activators
325                                                         create_nether_portal(i,origin,"x")
326                                                 else
327                                                         --print("try z")
328                                                         x_failed = true
329                                                         n_index = {}
330                                                         create_nether_portal(origin,origin,"z")
331                                                 end
332                                         elseif minetest.get_node(i).name ~= "nether:obsidian" then
333                                                 x_failed = true
334                                                 n_index = {}
335                                                 create_nether_portal(origin,origin,"z")
336                                         end
337                                 end
338                         end
339                 end
340                 end
341         --2d virtual memory map creation (z axis)
342         elseif axis == "z" then
343                 for z = -1,1 do
344                 for y = -1,1 do
345                         --index only direct neighbors
346                         if x_failed == true and portal_failure == false and (math.abs(z)+math.abs(y) == 1) then
347                                 local i = vector.add(pos,vector.new(0,y,z))
348                                 
349                                 local execute_collection = true
350                                 
351                                 if n_index[i.x] and n_index[i.x][i.y] then
352                                         if n_index[i.x][i.y][i.z] then
353                                                 execute_collection = false
354                                         end
355                                 end     
356                                 
357                                 if execute_collection == true then
358                                         --print(minetest.get_node(i).name)
359                                         --index air
360                                         if minetest.get_node(i).name == "air" then
361                                                 if vector.distance(i,origin) < 50 then
362                                                         --add data to both maps
363                                                         if not n_index[i.x] then n_index[i.x] = {} end
364                                                         if not n_index[i.x][i.y] then n_index[i.x][i.y] = {} end
365                                                         n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}                             
366                                                         --the data to the 3d array must be written to memory before this is executed
367                                                         --or a stack overflow occurs!!!
368                                                         --pass down info for activators
369                                                         create_nether_portal(i,origin,"z")
370                                                 else
371                                                         --print("portal failed")
372                                                         portal_failure = true
373                                                         n_index = {}
374                                                         --print("try z")
375                                                 end
376                                         elseif minetest.get_node(i).name ~= "nether:obsidian" then
377                                                 --print("portal failed")
378                                                 portal_failure = true
379                                                 n_index = {}
380                                         end
381                                 end
382                         end
383                 end
384                 end
385         end
386 end
387
388 --creates a nether portal in the nether
389 --this essentially makes it so you have to move 30 away from one portal to another otherwise it will travel to an existing portal
390 local nether_origin_pos = nil
391 local function spawn_portal_into_nether_callback(blockpos, action, calls_remaining, param)
392         if calls_remaining == 0 then
393                 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
394                                 
395                 if not portal_exists then
396                         local min = vector.subtract(nether_origin_pos,30)
397                         local max = vector.add(nether_origin_pos,30)
398                         local platform = minetest.find_nodes_in_area_under_air(min, max, {"nether:netherrack","main:lava"})
399                         
400                         if platform and next(platform) then
401                                 --print("setting the platform")
402                                 local platform_location = platform[math.random(1,table.getn(platform))]
403                                 
404                                 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
405                         else
406                                 --print("generate a portal within netherrack")
407                                 minetest.place_schematic(nether_origin_pos, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
408                         end
409                 else
410                         --print("portal exists, utilizing")
411                 end
412                 nether_origin_pos = nil
413         end
414 end
415 --creates nether portals in the overworld
416 local function spawn_portal_into_overworld_callback(blockpos, action, calls_remaining, param)
417         if calls_remaining == 0 then
418                 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
419                                 
420                 if not portal_exists then
421                         local min = vector.subtract(nether_origin_pos,30)
422                         local max = vector.add(nether_origin_pos,30)
423                         local platform = minetest.find_nodes_in_area_under_air(min, max, {"main:stone","main:water","main:grass","main:sand","main:dirt"})
424                         
425                         if platform and next(platform) then
426                                 --print("setting the platform")
427                                 local platform_location = platform[math.random(1,table.getn(platform))]
428                                 
429                                 minetest.place_schematic(platform_location, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
430                         else
431                                 --print("generate a portal within overworld stone")
432                                 minetest.place_schematic(nether_origin_pos, portalSchematic,"0",nil,true,"place_center_x, place_center_z")
433                         end
434                 else
435                         --print("portal exists, utilizing")
436                 end
437                 nether_origin_pos = nil
438         end
439 end
440
441
442 local function generate_nether_portal_in_nether(pos)
443         if pos.y > -10033 then
444                 --center the location to the lava height
445                 pos.y = -15000--+math.random(-30,30)    
446                 nether_origin_pos = pos
447                 
448                 local min = vector.subtract(nether_origin_pos,30)
449                 local max = vector.add(nether_origin_pos,30)
450                 
451                 --force load the area
452                 minetest.emerge_area(min, max, spawn_portal_into_nether_callback)
453         else
454                 --center the location to the water height
455                 pos.y = 0--+math.random(-30,30) 
456                 nether_origin_pos = pos
457                 --prefer height for mountains
458                 local min = vector.subtract(nether_origin_pos,vector.new(30,30,30))
459                 local max = vector.add(nether_origin_pos,vector.new(30,120,30))
460                 
461                 --force load the area
462                 minetest.emerge_area(min, max, spawn_portal_into_overworld_callback)
463         end
464 end
465
466
467 --modify the map with the collected data
468 local function portal_modify_map(n_copy)
469         local sorted_table = {}
470         local created_portal = false
471         for x,datax in pairs(n_copy) do
472                 for y,datay in pairs(datax) do
473                         for z,index in pairs(datay) do
474                                 --try to create a return side nether portal
475                                 if created_portal == false then
476                                         created_portal = true
477                                         generate_nether_portal_in_nether(vector.new(x,y,z))
478                                 end
479                                 table.insert(sorted_table, vector.new(x,y,z))
480                         end
481                 end
482         end
483         minetest.bulk_set_node(sorted_table, {name="nether:portal"})
484 end
485
486 -------------------------------------------------------------------------------------------
487 --the teleporter parts - stored here for now so I can read from other functions
488 local teleporting_player = nil
489 local function teleport_to_overworld(blockpos, action, calls_remaining, param)
490         if calls_remaining == 0 then
491                 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
492                 if portal_exists then
493                         print(teleporting_player)
494                         if teleporting_player then
495                                 teleporting_player:set_pos(portal_exists)
496                         end
497                 end
498                 teleporting_player = nil
499         end
500 end
501 local function teleport_to_nether(blockpos, action, calls_remaining, param)
502         if calls_remaining == 0 then
503                 local portal_exists = minetest.find_node_near(nether_origin_pos, 30, {"nether:portal"})
504                 if portal_exists then
505                         print(teleporting_player)
506                         if teleporting_player then
507                                 teleporting_player:set_pos(portal_exists)
508                         end
509                 end
510                 teleporting_player = nil
511         end
512 end
513
514 --this initializes all teleporter commands from the client
515 minetest.register_on_modchannel_message(function(channel_name, sender, message)
516         if channel_name == "nether_teleporters" then
517                 local player = minetest.get_player_by_name(sender)
518                 local pos = player:get_pos()
519                 
520                 if pos.y > -10033 then
521                         --center the location to the lava height
522                         pos.y = -15000--+math.random(-30,30)    
523                         nether_origin_pos = pos
524                         
525                         local min = vector.subtract(nether_origin_pos,30)
526                         local max = vector.add(nether_origin_pos,30)
527                         
528                         --force load the area
529                         teleporting_player = player
530                         minetest.emerge_area(min, max, teleport_to_nether)
531                 else
532                         --center the location to the water height
533                         pos.y = 0--+math.random(-30,30) 
534                         nether_origin_pos = pos
535                         --prefer height for mountains
536                         local min = vector.subtract(nether_origin_pos,vector.new(30,30,30))
537                         local max = vector.add(nether_origin_pos,vector.new(30,120,30))
538                         
539                         --force load the area
540                         teleporting_player = player
541                         minetest.emerge_area(min, max, teleport_to_overworld)
542                 end
543         end
544 end)
545 -------------------------------------------------------------------------------------------
546
547 -------------------------------------------------------------------------------
548
549 local destroy_n_index = {}
550 local destroy_portal_failure = false
551 local destroy_x_failed = false
552
553 --this can be used globally to create nether portals from obsidian
554 function destroy_nether_portal(pos,origin,axis)
555         --create the origin node for stored memory
556         if not origin then
557                 origin = pos
558         end             
559         --3d virtual memory map creation (x axis)
560         for x = -1,1 do
561         for z = -1,1 do
562         for y = -1,1 do
563                 --index only direct neighbors
564                 if (math.abs(x)+math.abs(z)+math.abs(y) == 1) then
565                         local i = vector.add(pos,vector.new(x,y,z))
566                         
567                         local execute_collection = true
568                         
569                         if destroy_n_index[i.x] and destroy_n_index[i.x][i.y] then
570                                 if destroy_n_index[i.x][i.y][i.z] then
571                                         execute_collection = false
572                                 end
573                         end     
574                         
575                         if execute_collection == true then
576                                 --print(minetest.get_node(i).name)
577                                 --index air
578                                 if minetest.get_node(i).name == "nether:portal" then
579                                         if vector.distance(i,origin) < 50 then
580                                                 --add data to both maps
581                                                 if not destroy_n_index[i.x] then destroy_n_index[i.x] = {} end
582                                                 if not destroy_n_index[i.x][i.y] then destroy_n_index[i.x][i.y] = {} end
583                                                 destroy_n_index[i.x][i.y][i.z] = {nether_portal=1} --get_group(i,"redstone_power")}                             
584                                                 --the data to the 3d array must be written to memory before this is executed
585                                                 --or a stack overflow occurs!!!
586                                                 --pass down info for activators
587                                                 destroy_nether_portal(i,origin,"z")
588                                         end
589                                 end
590                         end
591                 end
592         end
593         end
594         end
595 end
596
597 --modify the map with the collected data
598 local function destroy_portal_modify_map(destroy_n_copy)
599         local destroy_sorted_table = {}
600         for x,datax in pairs(destroy_n_copy) do
601                 for y,datay in pairs(datax) do
602                         for z,index in pairs(datay) do
603                                 table.insert(destroy_sorted_table, vector.new(x,y,z))
604                         end
605                 end
606         end
607         minetest.bulk_set_node(destroy_sorted_table, {name="air"})
608 end
609
610 minetest.register_globalstep(function(dtime)
611         --if indexes exist then calculate redstone
612         if n_index and next(n_index) and portal_failure == false then
613                 --create the old version to help with deactivation calculation
614                 local n_copy = table.copy(n_index)
615                 portal_modify_map(n_copy)
616                 portal_failure = false
617         end
618         if x_failed == true then
619                 x_failed = false
620         end
621         if portal_failure == true then
622                 portal_failure = false
623         end
624         --clear the index to avoid cpu looping wasting processing power
625         n_index = {}
626         
627         
628         --if indexes exist then calculate redstone
629         if destroy_n_index and next(destroy_n_index) and destroy_portal_failure == false then
630                 --create the old version to help with deactivation calculation
631                 local destroy_n_copy = table.copy(destroy_n_index)
632                 destroy_portal_modify_map(destroy_n_copy)
633         end
634         --clear the index to avoid cpu looping wasting processing power
635         destroy_n_index = {}
636 end)