asteroid_layer_helpers.lua 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. -- submodule
  2. otherworlds.asteroids = {}
  3. -- Approximate realm limits.
  4. local XMIN = -33000
  5. local XMAX = 33000
  6. local ZMIN = -33000
  7. local ZMAX = 33000
  8. local ASCOT = 1.0 -- Large asteroid / comet nucleus noise threshold.
  9. local SASCOT = 1.0 -- Small asteroid / comet nucleus noise threshold.
  10. local STOT = 0.125 -- Asteroid stone threshold.
  11. local COBT = 0.05 -- Asteroid cobble threshold.
  12. local GRAT = 0.02 -- Asteroid gravel threshold.
  13. local ICET = 0.05 -- Comet ice threshold.
  14. local ATMOT = -0.2 -- Comet atmosphere threshold.
  15. local FISTS = 0.01 -- Fissure noise threshold at surface. Controls size of fissures and amount / size of fissure entrances.
  16. local FISEXP = 0.3 -- Fissure expansion rate under surface.
  17. local ORECHA = 3*3*3 -- Ore 1/x chance per stone node.
  18. local CPCHU = 0 -- Maximum craters per chunk.
  19. local CRMIN = 5 -- Crater radius minimum, radius includes dust and obsidian layers.
  20. local CRRAN = 8 -- Crater radius range.
  21. -- Note: for fewer large objects: increase the 'spread' numbers in 'np_large' noise parameters. For fewer small objects do the same in 'np_small'. Then tune size with 'ASCOT'.
  22. -- 3D Perlin noise 1 for large structures
  23. local np_large = {
  24. offset = 0,
  25. scale = 1,
  26. spread = {x=256, y=128, z=256},
  27. seed = -83928935,
  28. octaves = 5,
  29. persist = 0.6
  30. }
  31. -- 3D Perlin noise 3 for fissures
  32. local np_fissure = {
  33. offset = 0,
  34. scale = 1,
  35. spread = {x=64, y=64, z=64},
  36. seed = -188881,
  37. octaves = 4,
  38. persist = 0.5
  39. }
  40. -- 3D Perlin noise 4 for small structures
  41. local np_small = {
  42. offset = 0,
  43. scale = 1,
  44. spread = {x=128, y=64, z=128},
  45. seed = 1000760700090,
  46. octaves = 4,
  47. persist = 0.6
  48. }
  49. -- 3D Perlin noise 5 for ore selection
  50. local np_ores = {
  51. offset = 0,
  52. scale = 1,
  53. spread = {x=128, y=128, z=128},
  54. seed = -70242,
  55. octaves = 1,
  56. persist = 0.5
  57. }
  58. -- 3D Perlin noise 6 for comet atmosphere
  59. local np_latmos = {
  60. offset = 0,
  61. scale = 1,
  62. spread = {x=256, y=128, z=256},
  63. seed = -83928935,
  64. octaves = 3,
  65. persist = 0.6
  66. }
  67. -- 3D Perlin noise 7 for small comet atmosphere
  68. local np_satmos = {
  69. offset = 0,
  70. scale = 1,
  71. spread = {x=128, y=64, z=128},
  72. seed = 1000760700090,
  73. octaves = 2,
  74. persist = 0.6
  75. }
  76. -- On dignode function. Atmosphere flows into a dug hole.
  77. minetest.register_on_dignode(function(pos, oldnode, digger)
  78. if minetest.find_node_near(pos, 1, {"asteroid:atmos"}) then
  79. minetest.set_node(pos, {name = "asteroid:atmos"})
  80. end
  81. end)
  82. -- Generate on_generated function based on parameters
  83. function otherworlds.asteroids.create_on_generated(ymin, ymax, content_ids)
  84. local YMIN = ymin
  85. local YMAX = ymax
  86. local c_air = content_ids.c_air
  87. local c_stone = content_ids.c_stone
  88. local c_cobble = content_ids.c_cobble
  89. local c_gravel = content_ids.c_gravel
  90. local c_dust = content_ids.c_dust
  91. local c_ironore = content_ids.c_ironore
  92. local c_copperore = content_ids.c_copperore
  93. local c_goldore = content_ids.c_goldore
  94. local c_diamondore = content_ids.c_diamondore
  95. local c_meseore = content_ids.c_meseore
  96. local c_waterice = content_ids.c_waterice
  97. local c_atmos = content_ids.c_atmos
  98. local c_snowblock = content_ids.c_snowblock
  99. local c_obsidian = content_ids.c_obsidian
  100. local c_thennium = content_ids.c_thennium
  101. -- return the function closed over the upvalues we want
  102. return function(minp, maxp, seed)
  103. if minp.x < XMIN or maxp.x > XMAX
  104. or minp.y < YMIN or maxp.y > YMAX
  105. or minp.z < ZMIN or maxp.z > ZMAX then
  106. return
  107. end
  108. -- local t1 = os.clock()
  109. local x1 = maxp.x
  110. local y1 = maxp.y
  111. local z1 = maxp.z
  112. local x0 = minp.x
  113. local y0 = minp.y
  114. local z0 = minp.z
  115. --print ("[asteroid] chunk ("..x0.." "..y0.." "..z0..")")
  116. local sidelen = x1 - x0 + 1 -- chunk side length
  117. --local vplanarea = sidelen ^ 2 -- vertical plane area, used if calculating noise index from x y z
  118. local chulens = {x=sidelen, y=sidelen, z=sidelen}
  119. local minpos = {x=x0, y=y0, z=z0}
  120. local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
  121. local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
  122. local data = vm:get_data()
  123. local nvals1 = minetest.get_perlin_map(np_large, chulens):get3dMap_flat(minpos)
  124. local nvals3 = minetest.get_perlin_map(np_fissure, chulens):get3dMap_flat(minpos)
  125. local nvals4 = minetest.get_perlin_map(np_small, chulens):get3dMap_flat(minpos)
  126. local nvals5 = minetest.get_perlin_map(np_ores, chulens):get3dMap_flat(minpos)
  127. local nvals6 = minetest.get_perlin_map(np_latmos, chulens):get3dMap_flat(minpos)
  128. local nvals7 = minetest.get_perlin_map(np_satmos, chulens):get3dMap_flat(minpos)
  129. local ni = 1
  130. for z = z0, z1 do -- for each vertical plane do
  131. for y = y0, y1 do -- for each horizontal row do
  132. local vi = area:index(x0, y, z) -- LVM index for first node in x row
  133. for x = x0, x1 do -- for each node do
  134. local noise1abs = math.abs(nvals1[ni])
  135. local noise4abs = math.abs(nvals4[ni])
  136. local comet = false
  137. if nvals6[ni] < -(ASCOT + ATMOT) or (nvals7[ni] < -(SASCOT + ATMOT) and nvals1[ni] < ASCOT) then
  138. comet = true -- comet biome
  139. end
  140. if noise1abs > ASCOT or noise4abs > SASCOT then -- if below surface then
  141. local noise1dep = noise1abs - ASCOT -- noise1dep zero at surface, positive beneath
  142. if math.abs(nvals3[ni]) > FISTS + noise1dep * FISEXP then -- if no fissure then
  143. local noise4dep = noise4abs - SASCOT -- noise4dep zero at surface, positive beneath
  144. if not comet or (comet and (noise1dep > math.random() + ICET or noise4dep > math.random() + ICET)) then
  145. -- asteroid or asteroid materials in comet
  146. if noise1dep >= STOT or noise4dep >= STOT then
  147. -- stone/ores
  148. if math.random(ORECHA) == 2 then
  149. if nvals5[ni] > .6 then
  150. data[vi] = c_thennium
  151. elseif nvals5[ni] < -.6 then
  152. data[vi] = c_thennium
  153. elseif nvals5[ni] > 0.4 then
  154. data[vi] = c_goldore
  155. elseif nvals5[ni] < -0.4 then
  156. data[vi] = c_diamondore
  157. elseif nvals5[ni] > 0.2 then
  158. data[vi] = c_meseore
  159. elseif nvals5[ni] < -0.2 then
  160. data[vi] = c_copperore
  161. else
  162. data[vi] = c_ironore
  163. end
  164. else
  165. data[vi] = c_stone
  166. end
  167. elseif noise1dep >= COBT or noise4dep >= COBT then
  168. data[vi] = c_cobble
  169. elseif noise1dep >= GRAT or noise4dep >= GRAT then
  170. data[vi] = c_gravel
  171. else
  172. data[vi] = c_dust
  173. end
  174. else -- comet materials
  175. if noise1dep >= ICET or noise4dep >= ICET then
  176. data[vi] = c_waterice
  177. else
  178. data[vi] = c_snowblock
  179. end
  180. end
  181. elseif comet then -- fissures, if comet then add comet atmosphere
  182. data[vi] = c_atmos
  183. end
  184. elseif comet then -- if comet atmosphere then
  185. data[vi] = c_atmos
  186. end
  187. ni = ni + 1
  188. vi = vi + 1
  189. end
  190. end
  191. end
  192. -- craters
  193. for ci = 1, CPCHU do -- iterate
  194. local cr = CRMIN + math.floor(math.random() ^ 2 * CRRAN) -- exponential radius
  195. local cx = math.random(minp.x + cr, maxp.x - cr) -- centre x
  196. local cz = math.random(minp.z + cr, maxp.z - cr) -- centre z
  197. local comet = false
  198. local surfy = false
  199. for y = y1, y0 + cr, -1 do
  200. local vi = area:index(cx, y, cz) -- LVM index for node
  201. local nodeid = data[vi]
  202. if nodeid == c_dust
  203. or nodeid == c_gravel
  204. or nodeid == c_cobble then
  205. surfy = y
  206. break
  207. elseif nodename == c_snowblock
  208. or nodename == c_waterice then
  209. comet = true
  210. surfy = y
  211. break
  212. end
  213. end
  214. if surfy and y1 - surfy > 9 then -- if surface found and 8 node space above impact node then
  215. for x = cx - cr, cx + cr do -- for each plane do
  216. for z = cz - cr, cz + cr do -- for each column do
  217. for y = surfy - cr, surfy + cr do -- for each node do
  218. local vi = area:index(x, y, z) -- LVM index for node
  219. local nr = ((x - cx) ^ 2 + (y - surfy) ^ 2 + (z - cz) ^ 2) ^ 0.5
  220. if nr <= cr - 2 then
  221. if comet then
  222. data[vi] = c_atmos
  223. else
  224. data[vi] = c_air
  225. end
  226. elseif nr <= cr - 1 then
  227. local nodeid = data[vi]
  228. if nodeid == c_gravel
  229. or nodeid == c_cobble
  230. or nodeid == c_stone
  231. or nodeid == c_diamondore
  232. or nodeid == c_goldore
  233. or nodeid == c_meseore
  234. or nodeid == c_copperore
  235. or nodeid == c_ironore then
  236. data[vi] = c_dust
  237. end
  238. elseif nr <= cr then
  239. local nodeid = data[vi]
  240. if nodeid == c_cobble
  241. or nodeid == c_stone then
  242. data[vi] = c_obsidian -- obsidian buried under dust
  243. end
  244. end
  245. end
  246. end
  247. end
  248. end
  249. end
  250. vm:set_data(data)
  251. vm:set_lighting({day=0, night=0})
  252. vm:calc_lighting()
  253. vm:write_to_map(data)
  254. -- local chugent = math.ceil((os.clock() - t1) * 1000)
  255. --print ("[asteroid] time "..chugent.." ms")
  256. data = nil
  257. end
  258. end