papyrus.lua 4.2 KB

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