cactus.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. cactus = cactus or {}
  2. cactus.modpath = minetest.get_modpath("default")
  3. cactus.steptime = {min=60, max=60*6}
  4. cactus.plantname = "default:cactus"
  5. cactus.maxheight = 5
  6. cactus.minlight = 13
  7. -- Should return a random height for an individual plant to grow.
  8. function cactus.random_height()
  9. return math.floor(math.random(math.random(2, 3), math.random(3, 5)))
  10. end
  11. function cactus.is_sand_name(name)
  12. if minetest.get_item_group(name, "sand") ~= 0 then
  13. return true
  14. end
  15. end
  16. function cactus.has_sand(pos)
  17. local p = vector.add(pos, {x=0, y=-1, z=0})
  18. local name = minetest.get_node(p).name
  19. -- Must be on sand or grass.
  20. if cactus.is_sand_name(name) then
  21. return true
  22. end
  23. end
  24. function cactus.can_grow(pos)
  25. -- Must have sand nearby.
  26. if not cactus.has_sand(pos) then
  27. return
  28. end
  29. local positions = {
  30. {x=pos.x+1, y=pos.y, z=pos.z},
  31. {x=pos.x-1, y=pos.y, z=pos.z},
  32. {x=pos.x, y=pos.y, z=pos.z+1},
  33. {x=pos.x, y=pos.y, z=pos.z-1},
  34. }
  35. local air = 0
  36. for k, v in ipairs(positions) do
  37. if minetest.get_node(v).name == "air" then
  38. air = air + 1
  39. end
  40. end
  41. -- If cactus is tightly packed (not enough air) then cannot grow.
  42. if air < 2 then
  43. return
  44. end
  45. -- No check for water.
  46. return true
  47. end
  48. -- Obtain growth height from soil, initializing it if not done yet.
  49. function cactus.get_grow_height(pos)
  50. local meta = minetest.get_meta({x=pos.x, y=pos.y-1, z=pos.z})
  51. local maxh = meta:get_int("cactus_height")
  52. if maxh == 0 then
  53. maxh = cactus.random_height()
  54. meta:set_int("cactus_height", maxh)
  55. end
  56. return maxh
  57. end
  58. -- Should be called when plant is dug.
  59. function cactus.reset_grow_height_and_timer(pos)
  60. -- Find soil node below plant.
  61. local p = vector.new(pos)
  62. local name = minetest.get_node(p).name
  63. local d = 0
  64. while not cactus.is_sand_name(name) and d < cactus.maxheight do
  65. -- All except bottom-most node must be plant.
  66. if name ~= cactus.plantname then
  67. return
  68. end
  69. p.y = p.y - 1
  70. d = d + 1
  71. name = minetest.get_node(p).name
  72. end
  73. -- Must be on sand.
  74. if cactus.is_sand_name(name) then
  75. local meta = minetest.get_meta(p)
  76. local maxh = cactus.random_height()
  77. meta:set_int("cactus_height", maxh)
  78. else
  79. return
  80. end
  81. -- Restart timer for plant directly above soil.
  82. p.y = p.y + 1
  83. if minetest.get_node(p).name ~= cactus.plantname then
  84. return
  85. end
  86. local min = cactus.steptime.min
  87. local max = cactus.steptime.max
  88. minetest.get_node_timer(p):start(math.random(min, max))
  89. end
  90. -- Attempt to grow cactus.
  91. -- Return 0 means nothing to report.
  92. -- 10 means plant has reached max height.
  93. -- 11 means plant is rotated wrong.
  94. -- 12 means plant cannot grow because of ice.
  95. function cactus.grow(pos, node)
  96. -- Check if we can grow.
  97. if not cactus.can_grow(pos) then
  98. return 0
  99. end
  100. if node.param2 >= 4 then
  101. return 11
  102. end
  103. if minetest.find_node_near(pos, 2, "group:cold") then
  104. return 12
  105. end
  106. -- Get how high we can grow.
  107. local maxh = cactus.get_grow_height(pos)
  108. -- Find current height of plant.
  109. local height = 0
  110. while node.name == cactus.plantname and height < maxh do
  111. height = height + 1
  112. pos.y = pos.y + 1
  113. node = minetest.get_node(pos)
  114. end
  115. if height >= maxh then
  116. -- Plant has reached max height.
  117. return 10
  118. end
  119. -- Check if we have room to grow some more.
  120. if node.name ~= "air" then
  121. return 0
  122. end
  123. -- Check if we have enough light.
  124. if minetest.get_node_light(pos) < cactus.minlight then
  125. return 0
  126. end
  127. -- Grow!
  128. minetest.add_node(pos, {name = cactus.plantname})
  129. return 0
  130. end
  131. function cactus.on_construct(pos)
  132. -- Only the ground-level plant piece should have nodetimer.
  133. -- If plant is not placed on soil, it will never have nodetimer.
  134. if cactus.has_sand(pos) then
  135. local min = cactus.steptime.min
  136. local max = cactus.steptime.max
  137. minetest.get_node_timer(pos):start(math.random(min, max))
  138. end
  139. end
  140. function cactus.on_destruct(pos)
  141. cactus.reset_grow_height_and_timer(pos)
  142. end
  143. function cactus.on_timer(pos, elapsed)
  144. --minetest.chat_send_all("# Server: Plant timer @ " .. minetest.pos_to_string(pos) .. "!")
  145. local node = minetest.get_node(pos)
  146. local result = cactus.grow(pos, node)
  147. -- Plant has reached max height.
  148. if result == 10 then return end
  149. -- Plant is rotated wrong.
  150. if result == 11 then return end
  151. -- Plant cannot grow because of ice.
  152. if result == 12 then return end
  153. return true
  154. end
  155. function cactus.after_dig_node(pos, node, metadata, digger)
  156. if node.param2 >= 4 then
  157. return
  158. end
  159. default.dig_up(pos, node, digger)
  160. -- No return value.
  161. end
  162. if not cactus.run_once then
  163. local c = "cactus:core"
  164. local f = cactus.modpath .. "/cactus.lua"
  165. reload.register_file(c, f, false)
  166. cactus.run_once = true
  167. end