Nether mod for Minetest
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
7.4KB

  1. --[[
  2. Nether mod for minetest
  3. Copyright (C) 2013 PilzAdam
  4. Permission to use, copy, modify, and/or distribute this software for
  5. any purpose with or without fee is hereby granted, provided that the
  6. above copyright notice and this permission notice appear in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  8. WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  9. WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
  10. BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
  11. OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  12. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  13. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  14. SOFTWARE.
  15. ]]--
  16. -- Parameters
  17. local NETHER_CEILING = nether.DEPTH_CEILING
  18. local NETHER_FLOOR = nether.DEPTH_FLOOR
  19. local TCAVE = 0.6
  20. local BLEND = 128
  21. -- 3D noise
  22. local np_cave = {
  23. offset = 0,
  24. scale = 1,
  25. spread = {x = 384, y = 128, z = 384}, -- squashed 3:1
  26. seed = 59033,
  27. octaves = 5,
  28. persist = 0.7,
  29. lacunarity = 2.0,
  30. --flags = ""
  31. }
  32. -- Stuff
  33. local yblmin = NETHER_FLOOR + BLEND * 2
  34. local yblmax = NETHER_CEILING - BLEND * 2
  35. -- Mapgen
  36. dofile(nether.path .. "/mapgen_decorations.lua")
  37. -- Initialize noise object, localise noise and data buffers
  38. local nobj_cave = nil
  39. local nbuf_cave = {}
  40. local dbuf = {}
  41. -- Content ids
  42. local c_air = minetest.get_content_id("air")
  43. --local c_stone_with_coal = minetest.get_content_id("default:stone_with_coal")
  44. --local c_stone_with_iron = minetest.get_content_id("default:stone_with_iron")
  45. local c_stone_with_mese = minetest.get_content_id("default:stone_with_mese")
  46. local c_stone_with_diamond = minetest.get_content_id("default:stone_with_diamond")
  47. local c_stone_with_gold = minetest.get_content_id("default:stone_with_gold")
  48. --local c_stone_with_copper = minetest.get_content_id("default:stone_with_copper")
  49. local c_mese = minetest.get_content_id("default:mese")
  50. local c_gravel = minetest.get_content_id("default:gravel")
  51. local c_dirt = minetest.get_content_id("default:dirt")
  52. local c_sand = minetest.get_content_id("default:sand")
  53. local c_cobble = minetest.get_content_id("default:cobble")
  54. local c_mossycobble = minetest.get_content_id("default:mossycobble")
  55. local c_stair_cobble = minetest.get_content_id("stairs:stair_cobble")
  56. local c_lava_source = minetest.get_content_id("default:lava_source")
  57. local c_lava_flowing = minetest.get_content_id("default:lava_flowing")
  58. local c_water_source = minetest.get_content_id("default:water_source")
  59. local c_water_flowing = minetest.get_content_id("default:water_flowing")
  60. local c_glowstone = minetest.get_content_id("nether:glowstone")
  61. local c_nethersand = minetest.get_content_id("nether:sand")
  62. local c_netherbrick = minetest.get_content_id("nether:brick")
  63. local c_netherrack = minetest.get_content_id("nether:rack")
  64. -- On-generated function
  65. minetest.register_on_generated(function(minp, maxp, seed)
  66. if minp.y > NETHER_CEILING or maxp.y < NETHER_FLOOR then
  67. return
  68. end
  69. local x1 = maxp.x
  70. local y1 = math.min(maxp.y, NETHER_CEILING)
  71. local z1 = maxp.z
  72. local x0 = minp.x
  73. local y0 = math.max(minp.y, NETHER_FLOOR)
  74. local z0 = minp.z
  75. local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
  76. local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax}
  77. local data = vm:get_data(dbuf)
  78. local x11 = emax.x -- Limits of mapchunk plus mapblock shell
  79. local y11 = emax.y
  80. local z11 = emax.z
  81. local x00 = emin.x
  82. local y00 = emin.y
  83. local z00 = emin.z
  84. local ystride = x1 - x0 + 1
  85. local zstride = ystride * ystride
  86. local chulens = {x = ystride, y = ystride, z = ystride}
  87. local minposxyz = {x = x0, y = y0, z = z0}
  88. nobj_cave = nobj_cave or minetest.get_perlin_map(np_cave, chulens)
  89. local nvals_cave = nobj_cave:get_3d_map_flat(minposxyz, nbuf_cave)
  90. for y = y00, y11 do -- Y loop first to minimise tcave calculations
  91. local tcave
  92. local in_chunk_y = false
  93. if y >= y0 and y <= y1 then
  94. tcave = TCAVE
  95. if y > yblmax then tcave = TCAVE + ((y - yblmax) / BLEND) ^ 2 end
  96. if y < yblmin then tcave = TCAVE + ((yblmin - y) / BLEND) ^ 2 end
  97. in_chunk_y = true
  98. end
  99. for z = z00, z11 do
  100. local vi = area:index(x00, y, z) -- Initial voxelmanip index
  101. local ni
  102. local in_chunk_yz = in_chunk_y and z >= z0 and z <= z1
  103. for x = x00, x11 do
  104. if in_chunk_yz and x == x0 then
  105. -- Initial noisemap index
  106. ni = (z - z0) * zstride + (y - y0) * ystride + 1
  107. end
  108. local in_chunk_yzx = in_chunk_yz and x >= x0 and x <= x1 -- In mapchunk
  109. local id = data[vi] -- Existing node
  110. -- Cave air, cave liquids and dungeons are overgenerated,
  111. -- convert these throughout mapchunk plus shell
  112. if id == c_air or -- Air and liquids to air
  113. id == c_lava_source or
  114. id == c_lava_flowing or
  115. id == c_water_source or
  116. id == c_water_flowing then
  117. data[vi] = c_air
  118. -- Dungeons are preserved so we don't need
  119. -- to check for cavern in the shell
  120. elseif id == c_cobble or -- Dungeons (preserved) to netherbrick
  121. id == c_mossycobble or
  122. id == c_stair_cobble then
  123. data[vi] = c_netherbrick
  124. end
  125. if in_chunk_yzx then -- In mapchunk
  126. if nvals_cave[ni] > tcave then -- Only excavate cavern in mapchunk
  127. data[vi] = c_air
  128. elseif id == c_mese then -- Mese block to lava
  129. data[vi] = c_lava_source
  130. elseif id == c_stone_with_gold or -- Precious ores to glowstone
  131. id == c_stone_with_mese or
  132. id == c_stone_with_diamond then
  133. data[vi] = c_glowstone
  134. elseif id == c_gravel or -- Blob ore to nethersand
  135. id == c_dirt or
  136. id == c_sand then
  137. data[vi] = c_nethersand
  138. else -- All else to netherstone
  139. data[vi] = c_netherrack
  140. end
  141. ni = ni + 1 -- Only increment noise index in mapchunk
  142. end
  143. vi = vi + 1
  144. end
  145. end
  146. end
  147. vm:set_data(data)
  148. -- avoid generating decorations on the underside of the bottom of the nether
  149. if minp.y > NETHER_FLOOR and maxp.y < NETHER_CEILING then minetest.generate_decorations(vm) end
  150. vm:set_lighting({day = 0, night = 0}, minp, maxp)
  151. vm:calc_lighting()
  152. vm:update_liquids()
  153. vm:write_to_map()
  154. end)
  155. -- use knowledge of the nether mapgen algorithm to return a suitable ground level for placing a portal.
  156. -- player_name is optional, allowing a player to spawn a remote portal in their own protected areas.
  157. function nether.find_nether_ground_y(target_x, target_z, start_y, player_name)
  158. local nobj_cave_point = minetest.get_perlin(np_cave)
  159. local air = 0 -- Consecutive air nodes found
  160. local minp_schem, maxp_schem = nether.get_schematic_volume({x = target_x, y = 0, z = target_z}, nil, "nether_portal")
  161. local minp = {x = minp_schem.x, y = 0, z = minp_schem.z}
  162. local maxp = {x = maxp_schem.x, y = 0, z = maxp_schem.z}
  163. for y = start_y, math.max(NETHER_FLOOR + BLEND, start_y - 4096), -1 do
  164. local nval_cave = nobj_cave_point:get3d({x = target_x, y = y, z = target_z})
  165. if nval_cave > TCAVE then -- Cavern
  166. air = air + 1
  167. else -- Not cavern, check if 4 nodes of space above
  168. if air >= 4 then
  169. local portal_y = y + 1
  170. -- Check volume for non-natural nodes
  171. minp.y = minp_schem.y + portal_y
  172. maxp.y = maxp_schem.y + portal_y
  173. if nether.volume_is_natural_and_unprotected(minp, maxp, player_name) then
  174. return portal_y
  175. else -- Restart search a little lower
  176. nether.find_nether_ground_y(target_x, target_z, y - 16, player_name)
  177. end
  178. else -- Not enough space, reset air to zero
  179. air = 0
  180. end
  181. end
  182. end
  183. return math.max(start_y, NETHER_FLOOR + BLEND) -- Fallback
  184. end