init.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. -- Maze map generator mod for Minetest
  2. -- Copyright © 2017 Pedro Gimeno Fortea
  3. -- Many thanks to Paramat for the numerous tips with the flat world generator
  4. -- and understanding the VoxelManip, and the people at IRC for their support.
  5. -- Which height to use for the terrain
  6. local terrain_height = 0
  7. -- Flat world generator from here:
  8. -- https://gist.github.com/pgimeno/1e046dd6bacb1624a70b37af5ea1d805
  9. minetest.set_mapgen_setting('mg_name', 'flat', true)
  10. minetest.set_mapgen_setting('mgflat_ground_level', terrain_height, true)
  11. -- water has to be below ground level to not inundate everything;
  12. -- it can't be equal lest you spawn at (0,0,0).
  13. minetest.set_mapgen_setting('water_level', -31000, true)
  14. minetest.set_mapgen_setting('mg_flags', 'light, nocaves, nodungeons, nodecorations', true);
  15. minetest.clear_registered_biomes()
  16. minetest.clear_registered_ores()
  17. minetest.clear_registered_decorations()
  18. minetest.register_biome {
  19. name = "mazeworld",
  20. --node_dust = "",
  21. node_top = "default:dirt_with_dry_grass", -- layer 1
  22. depth_top = 1,
  23. -- node_filler = "default:dirt", -- layer 2 (not uniform)
  24. -- depth_filler = 0,
  25. node_stone = "default:desert_stone", -- layer 3 (all the way to the bottom)
  26. --node_water_top = "",
  27. --depth_water_top = ,
  28. --node_water = "",
  29. --node_river_water = "",
  30. y_min = -31000,
  31. y_max = 31000,
  32. heat_point = 50,
  33. humidity_point = 50,
  34. }
  35. -- <paramat> you can stack biomes on top of each other if you need changes of
  36. -- materials with depth
  37. -- Maze generator - a variant of the recursive nested algorithm
  38. -- with base size 2 and a method to make long walls less prominent (TODO)
  39. local wall_nodeid = minetest.get_content_id('default:sandstonebrick')
  40. local empty_nodeid = minetest.get_content_id('air')
  41. local maze_height = terrain_height + 1
  42. local worldseed = tonumber(minetest.get_mapgen_setting("seed"))
  43. -- These variables are used to pass values to the functions
  44. -- (a bit ugly, but more comfortable)
  45. local xmin, ymin, zmin, xmax, ymax, zmax
  46. local sx, sy, sxy, base, xbase, zbase
  47. -- This is the VoxelManip data. Make it a top-level local as recommended.
  48. local data = {}
  49. local function intersects(px, pz, size)
  50. return not (px + size - 1 < xmin or px > xmax
  51. or pz + size - 1 < zmin or pz > zmax)
  52. end
  53. -- Return a pseudorandom generator that generates a sequence
  54. -- which is always the same for a given size, 2D position,
  55. -- and world seed, but different for each.
  56. local function get_rng(px, pz, size)
  57. return PcgRandom(PcgRandom(worldseed, size):next() + px, pz)
  58. end
  59. local function setmaze(x, z, id)
  60. for y = 0, sx, sx do
  61. data[base + (z - zbase) * sxy + (x - xbase) + y] = id
  62. end
  63. end
  64. local function setwall(x, z)
  65. setmaze(x, z, wall_nodeid)
  66. end
  67. local function clearwall(x, z)
  68. setmaze(x, z, empty_nodeid)
  69. end
  70. local function mazegen_recursive(xpos, zpos, size)
  71. -- A size-2 maze is essentially a U-shape.
  72. local rng = get_rng(xpos, zpos, size)
  73. -- Pick up the direction where the wall is.
  74. local dir = rng:next(0, 3)
  75. if size == 2 then
  76. -- reached the end of the recursion - fill this 4x4 block
  77. -- first the fixed walls
  78. setwall(xpos, zpos)
  79. setwall(xpos + 1, zpos)
  80. setwall(xpos + 2, zpos)
  81. setwall(xpos + 3, zpos)
  82. setwall(xpos, zpos + 1)
  83. setwall(xpos, zpos + 2)
  84. setwall(xpos, zpos + 3)
  85. setwall(xpos + 2, zpos + 2)
  86. -- now the extra wall
  87. local ofsx = dir == 0 and 1 or dir == 2 and -1 or 0
  88. local ofsz = dir == 1 and 1 or dir == 3 and -1 or 0
  89. setwall(xpos + 2 + ofsx, zpos + 2 + ofsz)
  90. return
  91. end
  92. -- Test all 4 positions at this nesting level, recursing if the
  93. -- current position touches the block.
  94. for z = zpos, zpos + size, size do
  95. for x = xpos, xpos + size, size do
  96. if intersects(x, z, size) then
  97. mazegen_recursive(x, z, size / 2)
  98. end
  99. end
  100. end
  101. if dir ~= 0 then
  102. -- remove one random block from the wall that extends to the east
  103. local rnd = rng:next(0, size/2 - 1) * 2 + 1
  104. if intersects(xpos + size + rnd, zpos + size, 1) then
  105. clearwall(xpos + size + rnd, zpos + size)
  106. end
  107. end
  108. if dir ~= 1 then
  109. -- remove one random block from the wall that extends to the north
  110. local rnd = rng:next(0, size/2 - 1) * 2 + 1
  111. if intersects(xpos + size, zpos + size + rnd, 1) then
  112. clearwall(xpos + size, zpos + size + rnd)
  113. end
  114. end
  115. if dir ~= 2 then
  116. -- remove one random block from the wall that extends to the west
  117. local rnd = rng:next(0, size/2 - 1) * 2 + 1
  118. if intersects(xpos + size - rnd, zpos + size, 1) then
  119. clearwall(xpos + size - rnd, zpos + size)
  120. end
  121. end
  122. if dir ~= 3 then
  123. -- remove one random block from the wall that extends to the south
  124. local rnd = rng:next(0, size/2 - 1) * 2 + 1
  125. if intersects(xpos + size, zpos + size - rnd, 1) then
  126. clearwall(xpos + size, zpos + size - rnd)
  127. end
  128. end
  129. end
  130. minetest.register_on_generated(function (minp, maxp, blockseed)
  131. local vm, min, max = minetest.get_mapgen_object("voxelmanip")
  132. -- does block include maze_height or maze_height + 1?
  133. if minp.y <= maze_height and maxp.y >= maze_height
  134. or minp.y <= maze_height + 1 and maxp.y >= maze_height + 1
  135. then
  136. sx, sy = max.x - min.x + 1, max.y - min.y + 1
  137. sxy = sx * sy
  138. base = (maze_height - min.y) * sx + 1
  139. xbase, zbase = min.x, min.z
  140. xmin, ymin, zmin = minp.x, minp.y, minp.z
  141. xmax, ymax, zmax = maxp.x, maxp.y, maxp.z
  142. -- Prepare to modify the voxelmanip
  143. vm:get_data(data)
  144. mazegen_recursive(-32768, -32768, 32768)
  145. vm:set_data(data)
  146. vm:write_to_map()
  147. end
  148. end)