papyrus.lua 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. meta:mark_as_private("papyrus_height")
  47. end
  48. return maxh
  49. end
  50. -- Should be called when plant is dug.
  51. function papyrus.reset_grow_height_and_timer(pos)
  52. -- Find soil node below plant.
  53. local p = vector.new(pos)
  54. local name = minetest.get_node(p).name
  55. local d = 0
  56. while not papyrus.is_dirt_name(name) and d < papyrus.maxheight do
  57. -- All except bottom-most node must be plant.
  58. if name ~= papyrus.plantname then
  59. return
  60. end
  61. p.y = p.y - 1
  62. d = d + 1
  63. name = minetest.get_node(p).name
  64. end
  65. -- Must be on dirt or grass.
  66. if papyrus.is_dirt_name(name) then
  67. local meta = minetest.get_meta(p)
  68. local maxh = papyrus.random_height()
  69. meta:set_int("papyrus_height", maxh)
  70. meta:mark_as_private("papyrus_height")
  71. else
  72. return
  73. end
  74. -- Restart timer for plant directly above soil.
  75. p.y = p.y + 1
  76. if minetest.get_node(p).name ~= papyrus.plantname then
  77. return
  78. end
  79. local min = papyrus.steptime.min
  80. local max = papyrus.steptime.max
  81. minetest.get_node_timer(p):start(math_random(min, max))
  82. end
  83. -- Attempt to grow papyrus.
  84. -- Return 0 means nothing to report.
  85. -- 10 means plant has reached max height.
  86. function papyrus.grow(pos, node)
  87. -- Check if we can grow.
  88. if not papyrus.can_grow(pos) then
  89. return 0
  90. end
  91. if minetest.find_node_near(pos, 2, "group:cold") then
  92. return 12
  93. end
  94. -- Get how high we can grow.
  95. local maxh = papyrus.get_grow_height(pos)
  96. -- Find current height of plant.
  97. local height = 0
  98. while node.name == papyrus.plantname and height < maxh do
  99. height = height + 1
  100. pos.y = pos.y + 1
  101. node = minetest.get_node(pos)
  102. end
  103. if height >= maxh then
  104. -- Plant has reached max height.
  105. return 10
  106. end
  107. -- Check if we have room to grow some more.
  108. if node.name ~= "air" then
  109. return 0
  110. end
  111. -- Check if we have enough light.
  112. if minetest.get_node_light(pos) < papyrus.minlight then
  113. return 0
  114. end
  115. -- Grow!
  116. minetest.add_node(pos, {name = papyrus.plantname})
  117. return 0
  118. end
  119. function papyrus.on_construct(pos)
  120. -- Only the ground-level plant piece should have nodetimer.
  121. -- If plant is not placed on soil, it will never have nodetimer.
  122. if papyrus.has_dirt(pos) then
  123. local min = papyrus.steptime.min
  124. local max = papyrus.steptime.max
  125. minetest.get_node_timer(pos):start(math_random(min, max))
  126. end
  127. end
  128. function papyrus.on_destruct(pos)
  129. papyrus.reset_grow_height_and_timer(pos)
  130. end
  131. function papyrus.on_timer(pos, elapsed)
  132. --minetest.chat_send_all("# Server: Plant timer @ " .. minetest.pos_to_string(pos) .. "!")
  133. local node = minetest.get_node(pos)
  134. local result = papyrus.grow(pos, node)
  135. -- Plant has reached max height.
  136. if result == 10 then return end
  137. -- Plant cannot grow because of ice.
  138. if result == 12 then return end
  139. return true
  140. end
  141. function papyrus.after_dig_node(pos, node, metadata, digger)
  142. default.dig_up(pos, node, digger)
  143. -- No return value.
  144. end
  145. if not papyrus.run_once then
  146. local c = "papyrus:core"
  147. local f = papyrus.modpath .. "/papyrus.lua"
  148. reload.register_file(c, f, false)
  149. papyrus.run_once = true
  150. end