generator.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. -- Caverealm noise, choses when cave biomes can spawn and what is left stone.
  2. local noise1param3d = {
  3. offset = 0,
  4. scale = 1,
  5. spread = {x=128, y=128, z=128},
  6. seed = 708291,
  7. octaves = 6,
  8. persist = 0.7,
  9. lacunarity = 2
  10. }
  11. -- Vein noise. Choses size & frequency of floor or roof ore veins.
  12. local noise2param3d = {
  13. offset = 0,
  14. scale = 1,
  15. spread = {x=128, y=128, z=128},
  16. seed = 48791,
  17. octaves = 4,
  18. persist = 0.5,
  19. lacunarity = 2
  20. }
  21. -- Biome noise, used to chose what cave biome should generate.
  22. local noise3param3d = {
  23. offset = 0,
  24. scale = 1,
  25. spread = {x=512, y=512, z=512},
  26. seed = 127726,
  27. octaves = 4,
  28. persist = 0.7,
  29. lacunarity = 2
  30. }
  31. -- Content-IDs for the voxel manipulator.
  32. local c_air = minetest.get_content_id("air")
  33. local c_stone = minetest.get_content_id("default:stone")
  34. local c_cobble = minetest.get_content_id("cavestuff:cobble") -- Special nodetype.
  35. local c_mossy_cobble = minetest.get_content_id("default:mossycobble")
  36. local c_cobble_moss = minetest.get_content_id("cavestuff:cobble_with_moss")
  37. local c_cobble_lichen = minetest.get_content_id("cavestuff:cobble_with_lichen")
  38. local c_cobble_algae = minetest.get_content_id("cavestuff:cobble_with_algae")
  39. local c_cobble_salt = minetest.get_content_id("cavestuff:cobble_with_salt")
  40. local c_coal_block = minetest.get_content_id("default:coalblock")
  41. local c_quartz_block = minetest.get_content_id("quartz:block")
  42. local c_dark_obsidian = minetest.get_content_id("cavestuff:dark_obsidian")
  43. local c_thin_ice = minetest.get_content_id("ice:thin_ice")
  44. local c_ice = minetest.get_content_id("default:ice")
  45. local c_sandy_ice = minetest.get_content_id("sand:sand_with_ice_crystals")
  46. -- These tables are updated per chunk-generation iteration.
  47. -- Keeping them external improves performance according to MT Lua docs.
  48. local data = {} -- Voxelmanip data table external for performance.
  49. local noisemap1 = {}
  50. local noisemap2 = {}
  51. local noisemap3 = {}
  52. -- Mapgen notes: this algorithm does not create any caves. It populates caves
  53. -- already generated by the C++ mapgen. Use huge Valleys caves for best results.
  54. cavegen.generate = function(minp, maxp, seed)
  55. -- Do not run for chunks above or below the caverealm region.
  56. if minp.y > -5000 or maxp.y < -23000 then
  57. return
  58. end
  59. -- Grab the voxel manipulator.
  60. local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
  61. vm:get_data(data)
  62. local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
  63. local area2 = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} -- Noise area.
  64. local pr = PseudoRandom(seed + 71)
  65. local x1 = maxp.x
  66. local y1 = maxp.y
  67. local z1 = maxp.z
  68. local x0 = minp.x
  69. local y0 = minp.y
  70. local z0 = minp.z
  71. -- Compute side lengths.
  72. local side_len_x = ((x1-x0)+1)
  73. local side_len_y = ((y1-y0)+1)
  74. local side_len_z = ((z1-z0)+1)
  75. local sides3D = {x=side_len_x, y=side_len_y, z=side_len_z}
  76. local bp3d = {x=x0, y=y0, z=z0}
  77. local perlin1 = minetest.get_perlin_map(noise1param3d, sides3D)
  78. perlin1:get_3d_map_flat(bp3d, noisemap1)
  79. local perlin2 = minetest.get_perlin_map(noise2param3d, sides3D)
  80. perlin2:get_3d_map_flat(bp3d, noisemap2)
  81. local perlin3 = minetest.get_perlin_map(noise3param3d, sides3D)
  82. perlin3:get_3d_map_flat(bp3d, noisemap3)
  83. local floor = math.floor
  84. local ceil = math.ceil
  85. local abs = math.abs
  86. local clamp = function(v, l, u)
  87. if v < l then return l end
  88. if v > u then return u end
  89. return v
  90. end
  91. -- Compute caverealm threshold. 0 = no caverealm, 1 = max possible.
  92. local compute_threshold = function(y)
  93. -- Height values outside outer range result in 0.
  94. if y > -5000 then
  95. return 0
  96. elseif y > -17000 then
  97. -- Y is below -5k and above -10k. Need fade!
  98. local a = (y+5000)/12000 -- Get value between 1 and 0.
  99. return abs(a)
  100. elseif y > -22000 then
  101. return 1
  102. elseif y > -23000 then
  103. -- Y is below -22k and above -23k. Need fade!
  104. local a = (y+23000)/1000 -- Get value between 1 and 0.
  105. return a
  106. else
  107. return 0
  108. end
  109. end
  110. -- These tables will be filled with locations for decorations,
  111. -- calculated by the voxel manipulator code. After the voxel manipulator
  112. -- runs, decorations should be placed at locations in these tables.
  113. local glowstrings = {}
  114. local rooficicles = {}
  115. local floorcicles = {}
  116. local mycenashrom = {}
  117. local fungusshrom = {}
  118. local cavespikeps = {}
  119. local saltcrystal = {}
  120. local moongemspos = {}
  121. local sapphrspike = {} -- Sapphire spikes.
  122. local emraldspike = {} -- Emerald spikes.
  123. local emraldspik2 = {} -- Emerald spikes.
  124. local rubyspikes1 = {}
  125. local amethystspk = {}
  126. local mesespikes1 = {}
  127. local swaterwells = {}
  128. for z = z0, z1 do
  129. for x = x0, x1 do
  130. for y = y0, y1 do
  131. -- Get index into 3D noise array.
  132. local ni3 = area2:index(x, y, z)
  133. local n1 = noisemap1[ni3]
  134. local n2 = noisemap2[ni3]
  135. local n3 = noisemap3[ni3]
  136. local threshold = compute_threshold(y)
  137. local rn = clamp(abs(n1), 0, 1) -- Caverealm noise.
  138. if rn <= threshold then
  139. local vp = area:index(x, y, z)
  140. local vu = area:index(x, y+1, z)
  141. local vd = area:index(x, y-1, z)
  142. local ip = data[vp]
  143. local iu = data[vu]
  144. local id = data[vd]
  145. -- If found cave ceiling.
  146. if ip == c_stone and id == c_air then
  147. data[vp] = c_cobble -- Plain cobble on roof.
  148. if abs(n2) < 0.04 then
  149. data[vd] = c_quartz_block
  150. elseif abs(n2) < 0.09 then
  151. data[vd] = c_coal_block
  152. elseif pr:next(1, 100) == 1 then -- Glow worms.
  153. glowstrings[#glowstrings+1] = {x=x, y=y-1, z=z}
  154. elseif pr:next(1, 100) == 1 then -- Icicles
  155. rooficicles[#rooficicles+1] = {x=x, y=y-1, z=z}
  156. data[vp] = c_thin_ice -- Override cobble roof.
  157. end
  158. end
  159. if rn <= threshold*0.8 then
  160. -- If found raw cave floor.
  161. -- We check floor after ceiling in case floor and ceiling
  162. -- intersect. This way, floor material takes precedence.
  163. if ip == c_stone and iu == c_air then
  164. data[vp] = c_cobble -- Plain cobble under floor surface.
  165. if abs(n2) < 0.05 then
  166. data[vu] = c_dark_obsidian
  167. else
  168. -- Chose floor type to place. Floor type determines biome.
  169. local bn = abs(n3)
  170. if bn < 0.1 then
  171. data[vu] = c_cobble_moss
  172. elseif bn < 0.3 then
  173. data[vu] = c_cobble_algae
  174. elseif bn < 0.6 then
  175. data[vu] = c_cobble_lichen
  176. elseif bn < 0.8 then
  177. data[vu] = c_cobble_salt
  178. elseif bn < 0.9 then
  179. data[vu] = c_sandy_ice
  180. else
  181. data[vu] = c_thin_ice
  182. if bn > 1.0 then
  183. data[vp] = c_ice -- Override cobble floor.
  184. end
  185. end
  186. end
  187. end
  188. end
  189. -- Floor & roof types have changed, re-read them.
  190. ip = data[vp]
  191. iu = data[vu]
  192. id = data[vd]
  193. -- If found generated ice cave floor.
  194. -- Generate position tables for ice biome decorations.
  195. if ip == c_thin_ice and iu == c_air then
  196. if pr:next(1, 100) == 1 then
  197. floorcicles[#floorcicles+1] = {x=x, y=y+1, z=z}
  198. data[vp] = c_ice
  199. end
  200. end
  201. -- If found floor of biome suitable for mushrooms.
  202. -- Generate position tables for mushrooms.
  203. if (ip == c_cobble_moss or
  204. ip == c_cobble_algae or
  205. ip == c_cobble_lichen) and iu == c_air then
  206. if pr:next(1, 100) == 1 then
  207. mycenashrom[#mycenashrom+1] = {x=x, y=y+1, z=z}
  208. data[vp] = c_mossy_cobble
  209. elseif pr:next(1, 70) == 1 then
  210. fungusshrom[#fungusshrom+1] = {x=x, y=y+1, z=z}
  211. data[vp] = c_mossy_cobble
  212. end
  213. end
  214. if ip == c_cobble_salt and iu == c_air then
  215. if pr:next(1, 100) == 1 then
  216. saltcrystal[#saltcrystal+1] = {x=x, y=y+1, z=z}
  217. end
  218. end
  219. if ip == c_cobble_lichen and iu == c_air then
  220. if pr:next(1, 200) == 1 then
  221. moongemspos[#moongemspos+1] = {x=x, y=y+1, z=z}
  222. end
  223. end
  224. -- Water wells.
  225. if pr:next(1, 40) == 1 then
  226. if iu == c_air and ip == c_cobble_moss then
  227. swaterwells[#swaterwells+1] = {x=x, y=y, z=z}
  228. end
  229. end
  230. -- Chance for spikes is deceptively high.
  231. -- Most of these locations will be rejected due to ground checks later.
  232. if pr:next(1, 40) == 1 then
  233. if iu == c_air then
  234. if ip == c_cobble_lichen then
  235. sapphrspike[#sapphrspike+1] = {x=x, y=y+1, z=z}
  236. end
  237. if ip == c_cobble_moss then
  238. emraldspike[#emraldspike+1] = {x=x, y=y+1, z=z}
  239. end
  240. if ip == c_cobble_algae then
  241. emraldspik2[#emraldspik2+1] = {x=x, y=y+1, z=z}
  242. end
  243. end
  244. -- Ceiling spikes.
  245. if ip == c_cobble and id == c_air then
  246. local which = pr:next(1, 3)
  247. if which == 1 then
  248. mesespikes1[#mesespikes1+1] = {x=x, y=y-1, z=z}
  249. elseif which == 2 then
  250. rubyspikes1[#rubyspikes1+1] = {x=x, y=y-1, z=z}
  251. elseif which == 3 then
  252. amethystspk[#amethystspk+1] = {x=x, y=y-1, z=z}
  253. end
  254. end
  255. end
  256. -- If found raw stone floor (edges of caverealm biomes).
  257. -- Generate positions for rock spikes.
  258. if ip == c_stone and iu == c_air then
  259. if pr:next(1, 40) == 1 then
  260. cavespikeps[#cavespikeps+1] = {x=x, y=y+1, z=z}
  261. end
  262. end
  263. end
  264. end -- For all in Y coordinates.
  265. end -- For all in X coordinates.
  266. end -- For all in Z coordinates.
  267. -- Finalize voxel manipulator.
  268. vm:set_data(data)
  269. vm:set_lighting({day=0, night=0})
  270. vm:calc_lighting()
  271. vm:update_liquids()
  272. vm:write_to_map()
  273. -- Place glow worms.
  274. -- Glow worms come in columns of nodes,
  275. -- so this needs a special algorithm.
  276. for k, v in ipairs(glowstrings) do
  277. local len = pr:next(1, pr:next(2, 5))
  278. for i=0, len, 1 do
  279. local pos = {x=v.x, y=v.y-i, z=v.z}
  280. if minetest.get_node(pos).name == "air" then
  281. minetest.set_node(pos, {name="cavestuff:glow_worm"})
  282. else
  283. break
  284. end
  285. end
  286. end
  287. -- Function for quickly placing 1-node sized decorations.
  288. local place_decorations = function(nn, tt)
  289. for k, v in ipairs(tt) do
  290. local pos = {x=v.x, y=v.y, z=v.z}
  291. if minetest.get_node(pos).name == "air" then
  292. minetest.set_node(pos, {name=nn})
  293. end
  294. end
  295. end
  296. place_decorations("cavestuff:icicle_down", rooficicles)
  297. place_decorations("cavestuff:icicle_up", floorcicles)
  298. place_decorations("cavestuff:mycena", mycenashrom)
  299. place_decorations("cavestuff:fungus", fungusshrom)
  300. -- Place stone spikes.
  301. for k, v in ipairs(cavespikeps) do
  302. local pos = {x=v.x, y=v.y, z=v.z}
  303. if minetest.get_node(pos).name == "air" then
  304. minetest.set_node(pos, {name="cavestuff:spike" .. pr:next(1, 4)})
  305. end
  306. end
  307. -- Place salt crystals.
  308. for k, v in ipairs(saltcrystal) do
  309. local pos = {x=v.x, y=v.y, z=v.z}
  310. if minetest.get_node(pos).name == "air" then
  311. minetest.set_node(pos, {name="cavestuff:saltcrystal" .. pr:next(1, 4)})
  312. end
  313. end
  314. -- Place moon gems.
  315. for k, v in ipairs(moongemspos) do
  316. local pos = {x=v.x, y=v.y, z=v.z}
  317. if minetest.get_node(pos).name == "air" then
  318. minetest.set_node(pos, {name="cavestuff:bluecrystal" .. pr:next(1, 4)})
  319. end
  320. end
  321. local place_spike_up = function(gname, basename, spikename, postable)
  322. for k, v in ipairs(postable) do
  323. -- Check foundation to see if a spike can be placed here.
  324. local floorcheck = {
  325. {x=v.x, y=v.y-1, z=v.z},
  326. {x=v.x-1, y=v.y-1, z=v.z},
  327. {x=v.x+1, y=v.y-1, z=v.z},
  328. {x=v.x, y=v.y-1, z=v.z-1},
  329. {x=v.x, y=v.y-1, z=v.z+1},
  330. }
  331. for i, j in ipairs(floorcheck) do
  332. if minetest.get_node(j).name ~= gname then
  333. return -- Bad foundation.
  334. end
  335. end
  336. -- Foundation is solid.
  337. -- Build crystaline base.
  338. local crystalbase = {
  339. {x=v.x, y=v.y, z=v.z},
  340. {x=v.x-1, y=v.y, z=v.z},
  341. {x=v.x+1, y=v.y, z=v.z},
  342. {x=v.x, y=v.y, z=v.z-1},
  343. {x=v.x, y=v.y, z=v.z+1},
  344. {x=v.x-1, y=v.y, z=v.z-1},
  345. {x=v.x+1, y=v.y, z=v.z-1},
  346. {x=v.x-1, y=v.y, z=v.z+1},
  347. {x=v.x+1, y=v.y, z=v.z+1},
  348. {x=v.x-2, y=v.y, z=v.z},
  349. {x=v.x+2, y=v.y, z=v.z},
  350. {x=v.x, y=v.y, z=v.z-2},
  351. {x=v.x, y=v.y, z=v.z+2},
  352. }
  353. for i, j in ipairs(crystalbase) do
  354. minetest.set_node(j, {name=basename})
  355. end
  356. -- Build upwards pointing spike.
  357. local l = pr:next(7, 20)
  358. local l1 = pr:next(floor(l/3), floor((l/3)*2))
  359. local l2 = pr:next(floor(l/3), floor((l/3)*2))
  360. local l3 = pr:next(floor(l/3), floor((l/3)*2))
  361. local l4 = pr:next(floor(l/3), floor((l/3)*2))
  362. local buildspike = function(pos, len)
  363. for i=0, len, 1 do
  364. local p = {x=pos.x, y=pos.y+i, z=pos.z}
  365. -- Spikes grow through everything,
  366. -- but quit if at unloaded chunk border.
  367. if minetest.get_node(p).name == "ignore" then return end
  368. minetest.set_node(p, {name=spikename})
  369. end
  370. end
  371. buildspike({x=v.x, y=v.y+1, z=v.z}, l)
  372. buildspike({x=v.x-1, y=v.y+1, z=v.z}, l1)
  373. buildspike({x=v.x+1, y=v.y+1, z=v.z}, l2)
  374. buildspike({x=v.x, y=v.y+1, z=v.z-1}, l3)
  375. buildspike({x=v.x, y=v.y+1, z=v.z+1}, l4)
  376. end
  377. end
  378. local place_spike_down = function(gname, basename, spikename, postable)
  379. for k, v in ipairs(postable) do
  380. -- Check foundation to see if a spike can be placed here.
  381. local floorcheck = {
  382. {x=v.x, y=v.y+1, z=v.z},
  383. {x=v.x-1, y=v.y+1, z=v.z},
  384. {x=v.x+1, y=v.y+1, z=v.z},
  385. {x=v.x, y=v.y+1, z=v.z-1},
  386. {x=v.x, y=v.y+1, z=v.z+1},
  387. }
  388. for i, j in ipairs(floorcheck) do
  389. if minetest.get_node(j).name ~= gname then
  390. return -- Bad foundation.
  391. end
  392. end
  393. -- Foundation is solid.
  394. -- Build crystaline base.
  395. local crystalbase = {
  396. {x=v.x, y=v.y, z=v.z},
  397. {x=v.x-1, y=v.y, z=v.z},
  398. {x=v.x+1, y=v.y, z=v.z},
  399. {x=v.x, y=v.y, z=v.z-1},
  400. {x=v.x, y=v.y, z=v.z+1},
  401. {x=v.x-1, y=v.y, z=v.z-1},
  402. {x=v.x+1, y=v.y, z=v.z-1},
  403. {x=v.x-1, y=v.y, z=v.z+1},
  404. {x=v.x+1, y=v.y, z=v.z+1},
  405. {x=v.x-2, y=v.y, z=v.z},
  406. {x=v.x+2, y=v.y, z=v.z},
  407. {x=v.x, y=v.y, z=v.z-2},
  408. {x=v.x, y=v.y, z=v.z+2},
  409. }
  410. for i, j in ipairs(crystalbase) do
  411. minetest.set_node(j, {name=basename})
  412. end
  413. -- Build downwards pointing spike.
  414. local l = pr:next(7, 20)
  415. local l1 = pr:next(floor(l/3), floor((l/3)*2))
  416. local l2 = pr:next(floor(l/3), floor((l/3)*2))
  417. local l3 = pr:next(floor(l/3), floor((l/3)*2))
  418. local l4 = pr:next(floor(l/3), floor((l/3)*2))
  419. local buildspike = function(pos, len)
  420. for i=0, len, 1 do
  421. local p = {x=pos.x, y=pos.y-i, z=pos.z}
  422. -- Spikes grow through everything,
  423. -- but quit if at unloaded chunk border.
  424. if minetest.get_node(p).name == "ignore" then return end
  425. minetest.set_node(p, {name=spikename})
  426. end
  427. end
  428. buildspike({x=v.x, y=v.y-1, z=v.z}, l)
  429. buildspike({x=v.x-1, y=v.y-1, z=v.z}, l1)
  430. buildspike({x=v.x+1, y=v.y-1, z=v.z}, l2)
  431. buildspike({x=v.x, y=v.y-1, z=v.z-1}, l3)
  432. buildspike({x=v.x, y=v.y-1, z=v.z+1}, l4)
  433. end
  434. end
  435. local place_water_well = function(gname, postable)
  436. for k, v in ipairs(postable) do
  437. -- Check foundation to see if a spike can be placed here.
  438. local floorcheck = {
  439. {x=v.x, y=v.y, z=v.z},
  440. {x=v.x-1, y=v.y, z=v.z},
  441. {x=v.x+1, y=v.y, z=v.z},
  442. {x=v.x, y=v.y, z=v.z-1},
  443. {x=v.x, y=v.y, z=v.z+1},
  444. }
  445. for i, j in ipairs(floorcheck) do
  446. if minetest.get_node(j).name ~= gname then
  447. return -- Bad foundation.
  448. end
  449. end
  450. local offset = vector.new(-2, 0, -2)
  451. local pos = vector.add(v, offset)
  452. local path = cavegen.modpath .. "/caverealm_freshwater_well.mts"
  453. minetest.place_schematic(pos, path, "random", nil, true)
  454. end
  455. end
  456. place_spike_up(
  457. "cavestuff:cobble_with_lichen",
  458. "cavestuff:glow_sapphire_ore",
  459. "cavestuff:glow_sapphire",
  460. sapphrspike)
  461. place_spike_up(
  462. "cavestuff:cobble_with_moss",
  463. "cavestuff:glow_emerald_ore",
  464. "cavestuff:glow_emerald",
  465. emraldspike)
  466. place_spike_up(
  467. "cavestuff:cobble_with_algae",
  468. "cavestuff:glow_emerald_ore",
  469. "cavestuff:glow_emerald",
  470. emraldspik2)
  471. place_spike_down(
  472. "cavestuff:cobble",
  473. "cavestuff:glow_ruby_ore",
  474. "cavestuff:glow_ruby",
  475. rubyspikes1)
  476. place_spike_down(
  477. "cavestuff:cobble",
  478. "cavestuff:glow_amethyst_ore",
  479. "cavestuff:glow_amethyst",
  480. amethystspk)
  481. place_spike_down(
  482. "cavestuff:cobble",
  483. "default:stone_with_mese",
  484. "cavestuff:glow_mese",
  485. mesespikes1)
  486. place_water_well(
  487. "cavestuff:cobble_with_moss",
  488. swaterwells)
  489. end