trees.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. local random = math.random
  2. function default.can_grow(pos)
  3. local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
  4. if not node_under then return false end
  5. if minetest.get_item_group(node_under.name, "soil") == 0 then
  6. minetest.remove_node(pos)
  7. return false
  8. end
  9. return true
  10. end
  11. function default.enough_light(pos)
  12. local light_level = minetest.get_node_light(pos)
  13. if not light_level or light_level < 10 then
  14. return false
  15. end
  16. return true
  17. end
  18. local c_air = minetest.get_content_id("air")
  19. local c_apple = minetest.get_content_id("default:apple")
  20. local function add_trunk_and_leaves(data, a, pos, tree_cid, leaves_cid,
  21. height, size, iters, is_apple_tree)
  22. local x, y, z = pos.x, pos.y, pos.z
  23. -- Trunk
  24. for y_dist = 0, height - 1 do
  25. local vi = a:index(x, y + y_dist, z)
  26. if y_dist == 0 or data[vi] == c_air or data[vi] == leaves_cid then
  27. data[vi] = tree_cid
  28. end
  29. end
  30. -- Force leaves near the trunk
  31. for z_dist = -1, 1 do
  32. for y_dist = -size, 1 do
  33. local vi = a:index(x - 1, y + height + y_dist, z + z_dist)
  34. for x_dist = -1, 1 do
  35. if data[vi] == c_air then
  36. if is_apple_tree and random(1, 8) == 1 then
  37. data[vi] = c_apple
  38. else
  39. data[vi] = leaves_cid
  40. end
  41. end
  42. vi = vi + 1
  43. end
  44. end
  45. end
  46. -- Randomly add leaves in 2x2x2 clusters.
  47. for i = 1, iters do
  48. local clust_x = x + random(-size, size - 1)
  49. local clust_y = y + height + random(-size, 0)
  50. local clust_z = z + random(-size, size - 1)
  51. for xi = 0, 1 do
  52. for yi = 0, 1 do
  53. for zi = 0, 1 do
  54. local vi = a:index(clust_x + xi, clust_y + yi, clust_z + zi)
  55. if data[vi] == c_air then
  56. if is_apple_tree and random(1, 8) == 1 then
  57. data[vi] = c_apple
  58. else
  59. data[vi] = leaves_cid
  60. end
  61. end
  62. end
  63. end
  64. end
  65. end
  66. end
  67. local c_tree = minetest.get_content_id("default:tree")
  68. local c_leaves = minetest.get_content_id("default:leaves")
  69. function default.grow_tree(pos, is_apple_tree, bad)
  70. --[[
  71. NOTE: Tree-placing code is currently duplicated in the engine
  72. and in games that have saplings; both are deprecated but not
  73. replaced yet
  74. --]]
  75. if bad then
  76. error("Deprecated use of default.grow_tree")
  77. end
  78. local x, y, z = pos.x, pos.y, pos.z
  79. local height = random(4, 6)
  80. local vm = minetest.get_voxel_manip()
  81. local minp, maxp = vm:read_from_map(
  82. {x = pos.x - 2, y = pos.y, z = pos.z - 2},
  83. {x = pos.x + 2, y = pos.y + height + 1, z = pos.z + 2}
  84. )
  85. local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
  86. local data = vm:get_data()
  87. add_trunk_and_leaves(data, a, pos, c_tree, c_leaves, height, 2, 8, is_apple_tree)
  88. vm:set_data(data)
  89. vm:write_to_map()
  90. vm:update_map()
  91. end
  92. local c_jungletree = minetest.get_content_id("default:jungletree")
  93. local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
  94. function default.grow_jungletree(pos, bad)
  95. --[[
  96. NOTE: Tree-placing code is currently duplicated in the engine
  97. and in games that have saplings; both are deprecated but not
  98. replaced yet
  99. --]]
  100. if bad then
  101. error("Deprecated use of default.grow_jungletree")
  102. end
  103. local x, y, z = pos.x, pos.y, pos.z
  104. local height = random(8, 12)
  105. local vm = minetest.get_voxel_manip()
  106. local minp, maxp = vm:read_from_map(
  107. {x = pos.x - 3, y = pos.y - 1, z = pos.z - 3},
  108. {x = pos.x + 3, y = pos.y + height + 1, z = pos.z + 3})
  109. local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
  110. local data = vm:get_data()
  111. add_trunk_and_leaves(data, a, pos, c_jungletree, c_jungleleaves, height, 3, 30, false)
  112. -- Roots
  113. for z_dist = -1, 1 do
  114. local vi_1 = a:index(x - 1, y - 1, z + z_dist)
  115. local vi_2 = a:index(x - 1, y, z + z_dist)
  116. for x_dist = -1, 1 do
  117. if random(1, 3) >= 2 then
  118. if data[vi_1] == c_air then
  119. data[vi_1] = c_jungletree
  120. elseif data[vi_2] == c_air then
  121. data[vi_2] = c_jungletree
  122. end
  123. end
  124. vi_1 = vi_1 + 1
  125. vi_2 = vi_2 + 1
  126. end
  127. end
  128. vm:set_data(data)
  129. vm:write_to_map()
  130. vm:update_map()
  131. end
  132. function default.grow_sapling(pos)
  133. if not default.can_grow(pos) then return true end
  134. if minetest.find_node_near(pos, 1, {"group:tree", "group:sapling"}) then
  135. minetest.set_node(pos, {name="default:grass_"..math.random(1, 5)})
  136. return
  137. end
  138. -- Restart the timer with a shorter timeout, as we just wait for enough light
  139. if not default.enough_light(pos) then
  140. minetest.get_node_timer(pos):start(math.random(30, 480))
  141. return
  142. end
  143. default.grow_tree(pos, math.random(1, 8) == 1)
  144. end
  145. function default.grow_junglesapling(pos)
  146. if not default.can_grow(pos) then return true end
  147. if minetest.find_node_near(pos, 1, {"group:tree", "group:sapling"}) then
  148. minetest.set_node(pos, {name="default:junglegrass"})
  149. return
  150. end
  151. if not default.enough_light(pos) then
  152. minetest.get_node_timer(pos):start(math.random(30, 480))
  153. return
  154. end
  155. default.grow_jungletree(pos)
  156. end
  157. minetest.register_lbm({
  158. name = "default:convert_saplings_to_node_timer",
  159. nodenames = {"default:sapling", "default:junglesapling"},
  160. action = function(pos)
  161. minetest.get_node_timer(pos):start(math.random(300, 4800))
  162. end
  163. })