Giant mushrooms
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.

340 lines
8.4 KiB

6 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
8 years ago
6 years ago
9 years ago
7 years ago
8 years ago
6 years ago
6 years ago
8 years ago
8 years ago
9 years ago
8 years ago
7 years ago
8 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
8 years ago
7 years ago
8 years ago
8 years ago
9 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
6 years ago
9 years ago
7 years ago
7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
7 years ago
7 years ago
8 years ago
  1. local minetest = minetest --Should make things a bit faster.
  2. local c
  3. local function define_contents()
  4. c = {
  5. ignore = minetest.get_content_id("ignore"),
  6. air = minetest.get_content_id("air"),
  7. water = minetest.get_content_id("default:water_source"),
  8. stone = minetest.get_content_id("default:stone"),
  9. dirt = minetest.get_content_id("default:dirt"),
  10. desert_sand = minetest.get_content_id("default:desert_sand"),
  11. dry_shrub = minetest.get_content_id("default:dry_shrub"),
  12. ground = minetest.get_content_id("riesenpilz:ground"),
  13. riesenpilz_brown = minetest.get_content_id("riesenpilz:brown"),
  14. riesenpilz_red = minetest.get_content_id("riesenpilz:red"),
  15. riesenpilz_fly_agaric = minetest.get_content_id("riesenpilz:fly_agaric"),
  16. riesenpilz_lavashroom = minetest.get_content_id("riesenpilz:lavashroom"),
  17. riesenpilz_glowshroom = minetest.get_content_id("riesenpilz:glowshroom"),
  18. riesenpilz_parasol = minetest.get_content_id("riesenpilz:parasol"),
  19. TREE_STUFF = {
  20. minetest.get_content_id("default:tree"),
  21. minetest.get_content_id("default:leaves"),
  22. minetest.get_content_id("default:apple"),
  23. minetest.get_content_id("default:jungletree"),
  24. minetest.get_content_id("default:jungleleaves"),
  25. minetest.get_content_id("default:junglegrass"),
  26. },
  27. }
  28. end
  29. local grounds = {}
  30. local function is_ground(id)
  31. local is = grounds[id]
  32. if is ~= nil then
  33. return is
  34. end
  35. local data = minetest.registered_nodes[minetest.get_name_from_content_id(id)]
  36. if not data
  37. or data.paramtype == "light" then
  38. grounds[id] = false
  39. return false
  40. end
  41. local groups = data.groups
  42. if groups
  43. and (groups.crumbly == 3 or groups.soil == 1) then
  44. grounds[id] = true
  45. return true
  46. end
  47. grounds[id] = false
  48. return false
  49. end
  50. local toremoves = {}
  51. local function is_toremove(id)
  52. local is = toremoves[id]
  53. if is ~= nil then
  54. return is
  55. end
  56. local data = minetest.registered_nodes[minetest.get_name_from_content_id(id)]
  57. if not data then
  58. toremoves[id] = false
  59. return false
  60. end
  61. local groups = data.groups
  62. if groups
  63. and groups.flammable then
  64. toremoves[id] = true
  65. return true
  66. end
  67. toremoves[id] = false
  68. return false
  69. end
  70. local data = {}
  71. local area, pr
  72. local function make_circle(nam, pos, radius, chance)
  73. local circle = riesenpilz.circle(radius)
  74. for i = 1, #circle do
  75. if pr:next(1, chance) == 1 then
  76. local vi = area:indexp(vector.add(pos, circle[i]))
  77. if data[vi] == c.air
  78. and is_ground(data[vi - area.ystride]) then
  79. data[vi] = nam
  80. end
  81. end
  82. end
  83. end
  84. local nosmooth_rarity = 0.5
  85. local smooth_rarity_max = 0.6
  86. local smooth_rarity_min = 0.4
  87. local smooth_rarity_dif = smooth_rarity_max - smooth_rarity_min
  88. local perlin_scale = 500
  89. local contents_defined
  90. minetest.register_on_generated(function(minp, maxp, seed)
  91. if maxp.y <= 0
  92. or minp.y >= 150 then --avoid generation in the sky
  93. return
  94. end
  95. local x0,z0,x1,z1 = minp.x,minp.z,maxp.x,maxp.z -- Assume X and Z lengths are equal
  96. local perlin1 = minetest.get_perlin(51,3, 0.5, perlin_scale) --Get map specific perlin
  97. if not riesenpilz.always_generate then
  98. local biome_allowed
  99. for x = x0, x1, 16 do
  100. for z = z0, z1, 16 do
  101. if perlin1:get2d({x=x, y=z}) > nosmooth_rarity then
  102. biome_allowed = true
  103. break
  104. end
  105. end
  106. if biome_allowed then
  107. break
  108. end
  109. end
  110. if not biome_allowed then
  111. return
  112. end
  113. end
  114. local t1 = os.clock()
  115. riesenpilz.inform(("tries to generate a giant mushroom biome at: " ..
  116. "x=[%d; %d]; y=[%d; %d]; z=[%d; %d]"):format(minp.x, maxp.x, minp.y,
  117. maxp.y, minp.z, maxp.z), 2)
  118. if not contents_defined then
  119. define_contents()
  120. contents_defined = true
  121. end
  122. local divs = (maxp.x-minp.x);
  123. local num = 1
  124. local tab = {}
  125. pr = PseudoRandom(seed+68)
  126. local heightmap = minetest.get_mapgen_object("heightmap")
  127. local hmi = 1
  128. local hm_zstride = divs+1
  129. local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
  130. vm:get_data(data)
  131. area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
  132. for p_pos in area:iterp(minp, maxp) do --remove tree stuff
  133. local d_p_pos = data[p_pos]
  134. for _,nam in ipairs(c.TREE_STUFF) do
  135. if d_p_pos == nam then
  136. data[p_pos] = c.air
  137. break
  138. end
  139. end
  140. end
  141. for j=0,divs do
  142. for i=0,divs do
  143. local x,z = x0+i,z0+j
  144. --Check if we are in a "riesenpilz biome"
  145. local in_biome = false
  146. local test = perlin1:get2d({x=x, y=z})
  147. --smooth mapgen
  148. if riesenpilz.always_generate then
  149. in_biome = true
  150. elseif riesenpilz.smooth then
  151. if test >= smooth_rarity_max
  152. or (
  153. test > smooth_rarity_min
  154. and pr:next(1, 1000) <= ((test-smooth_rarity_min)/smooth_rarity_dif)*1000
  155. ) then
  156. in_biome = true
  157. end
  158. elseif test > nosmooth_rarity then
  159. in_biome = true
  160. end
  161. if in_biome then
  162. local ymin = math.max(heightmap[hmi]-5, minp.y)
  163. local ymax = math.min(heightmap[hmi]+20, maxp.y)
  164. -- skip the air part
  165. local ground
  166. local vi = area:index(x, ymax, z)
  167. for y = ymax, ymin, -1 do
  168. if data[vi] ~= c.air then
  169. ground = y
  170. break
  171. end
  172. vi = vi - area.ystride
  173. end
  174. local ground_y
  175. if ground then
  176. for y = ground, ymin, -1 do
  177. local d_p_pos = data[vi]
  178. if is_toremove(d_p_pos) then
  179. -- remove trees etc.
  180. data[vi] = c.air
  181. else
  182. if is_ground(d_p_pos) then
  183. ground_y = y
  184. heightmap[hmi] = y
  185. end
  186. break
  187. end
  188. vi = vi - area.ystride
  189. end
  190. end
  191. if ground_y then
  192. -- add ground and dirt below if needed
  193. data[vi] = c.ground
  194. for off = -1,-5,-1 do
  195. local p_pos = vi + off * area.ystride
  196. if not is_ground(data[p_pos])
  197. or data[p_pos] == c.dirt then
  198. break
  199. end
  200. data[p_pos] = c.dirt
  201. end
  202. local bigtype
  203. local boden = {x=x,y=ground_y+1,z=z}
  204. if pr:next(1,15) == 1 then
  205. data[vi + area.ystride] = c.dry_shrub
  206. elseif pr:next(1,80) == 1 then
  207. make_circle(c.riesenpilz_brown, boden, pr:next(3,4), 3)
  208. elseif pr:next(1,85) == 1 then
  209. make_circle(c.riesenpilz_parasol, boden, pr:next(3,5), 3)
  210. elseif pr:next(1,90) == 1 then
  211. make_circle(c.riesenpilz_red, boden, pr:next(4,5), 3)
  212. elseif pr:next(1,100) == 1 then
  213. make_circle(c.riesenpilz_fly_agaric, boden, 4, 3)
  214. elseif pr:next(1,340) == 10 then
  215. bigtype = 2
  216. elseif pr:next(1,380) == 1 then
  217. bigtype = 1
  218. elseif pr:next(1,390) == 20 then
  219. bigtype = 3
  220. elseif pr:next(1,800) == 7 then
  221. bigtype = 5
  222. elseif pr:next(1,4000) == 1 then
  223. make_circle(c.riesenpilz_lavashroom, boden, pr:next(5,6), 3)
  224. elseif pr:next(1,5000) == 1 then
  225. make_circle(c.riesenpilz_glowshroom, boden, 3, 3)
  226. elseif pr:next(1,6000) == 2 then
  227. if pr:next(1,200) == 15 then
  228. bigtype = 4
  229. elseif pr:next(1,2000) == 54 then
  230. bigtype = 6
  231. end
  232. end
  233. if bigtype then
  234. tab[num] = {bigtype, boden}
  235. num = num+1
  236. end
  237. end
  238. end
  239. hmi = hmi+1
  240. end
  241. end
  242. riesenpilz.inform("ground finished", 2, t1)
  243. local param2s
  244. if num ~= 1 then
  245. local t2 = os.clock()
  246. for _,v in pairs(tab) do
  247. local p = v[2]
  248. -- simple test for the distance to the biome border
  249. local found_border = false
  250. local dist = 5
  251. local xmin = math.max(minp.x, p.x - dist)
  252. local xmax = math.min(maxp.x, p.x + dist)
  253. local hm_vi = (p.z - minp.z) * hm_zstride + xmin - minp.x + 1
  254. for _ = xmin, xmax do
  255. if not heightmap[hm_vi] then
  256. found_border = true
  257. break
  258. end
  259. hm_vi = hm_vi+1
  260. end
  261. if not found_border then
  262. local zmin = math.max(minp.z, p.z - dist)
  263. local zmax = math.min(maxp.z, p.z + dist)
  264. hm_vi = (zmin - minp.z) * hm_zstride + p.x - minp.x + 1
  265. for _ = zmin, zmax do
  266. if not heightmap[hm_vi] then
  267. found_border = true
  268. break
  269. end
  270. hm_vi = hm_vi + hm_zstride
  271. end
  272. end
  273. if not found_border then
  274. local m = v[1]
  275. if m == 1 then
  276. riesenpilz.red(p, data, area)
  277. elseif m == 2 then
  278. riesenpilz.brown(p, data, area)
  279. elseif m == 3 then
  280. if not param2s then
  281. param2s = vm:get_param2_data()
  282. end
  283. riesenpilz.fly_agaric(p, data, area, param2s)
  284. elseif m == 4 then
  285. riesenpilz.lavashroom(p, data, area)
  286. elseif m == 5 then
  287. riesenpilz.parasol(p, data, area)
  288. elseif m == 6 then
  289. riesenpilz.red45(p, data, area)
  290. end
  291. end
  292. end
  293. riesenpilz.inform("giant shrooms generated", 2, t2)
  294. end
  295. local t2 = os.clock()
  296. vm:set_data(data)
  297. if param2s then
  298. vm:set_param2_data(param2s)
  299. end
  300. vm:set_lighting({day=0, night=0})
  301. vm:calc_lighting()
  302. vm:write_to_map()
  303. area = nil
  304. riesenpilz.inform("data set", 2, t2)
  305. riesenpilz.inform("done", 1, t1)
  306. end)