papyrus.lua 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. if not minetest.global_exists("papyrus") then papyrus = {} end
  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. function papyrus.on_place(itemstack, placer, pt)
  11. local under = pt.under
  12. local above = pt.above
  13. local node = minetest.get_node(under)
  14. local ndef = minetest.registered_nodes[node.name]
  15. -- Call on_rightclick if target node defines it.
  16. if ndef and ndef.on_rightclick and
  17. ((not placer) or (placer and not placer:get_player_control().sneak)) then
  18. return ndef.on_rightclick(under, node, placer, itemstack, pt) or itemstack
  19. end
  20. local fakestack = itemstack
  21. -- Pointing at bottom face? Place hanging papyrus.
  22. if above.y == (under.y - 1) then
  23. --minetest.chat_send_all('placing hanging variant')
  24. fakestack = ItemStack("default:papyrus2")
  25. fakestack:set_count(itemstack:get_count())
  26. end
  27. local stack, success, pos = minetest.item_place_node(fakestack, placer, pt)
  28. if success then
  29. itemstack:set_count(stack:get_count())
  30. return itemstack
  31. end
  32. end
  33. -- Should return a random height for an individual plant to grow.
  34. function papyrus.random_height()
  35. return math_floor(math_random(math_random(2, 3), math_random(3, 5)))
  36. end
  37. function papyrus.is_dirt_name(name)
  38. if name == "default:dirt_with_grass" or name == "default:dirt" or name == "moregrass:darkgrass" then
  39. return true
  40. end
  41. end
  42. function papyrus.has_dirt(pos)
  43. local p = vector.add(pos, {x=0, y=-1, z=0})
  44. local name = minetest.get_node(p).name
  45. -- Must be on dirt or grass.
  46. if papyrus.is_dirt_name(name) then
  47. return true
  48. end
  49. end
  50. function papyrus.can_grow(pos)
  51. -- Must have dirt nearby.
  52. if not papyrus.has_dirt(pos) then
  53. return
  54. end
  55. -- Must have water nearby.
  56. local p = vector.add(pos, {x=0, y=-1, z=0})
  57. if not minetest.find_node_near(p, 3, {"group:water"}) then
  58. return
  59. end
  60. return true
  61. end
  62. -- Obtain growth height from soil, initializing it if not done yet.
  63. function papyrus.get_grow_height(pos)
  64. local meta = minetest.get_meta({x=pos.x, y=pos.y-1, z=pos.z})
  65. local maxh = meta:get_int("papyrus_height")
  66. if maxh == 0 then
  67. maxh = papyrus.random_height()
  68. meta:set_int("papyrus_height", maxh)
  69. meta:mark_as_private("papyrus_height")
  70. end
  71. return maxh
  72. end
  73. -- Should be called when plant is dug.
  74. function papyrus.reset_grow_height_and_timer(pos)
  75. -- Find soil node below plant.
  76. local p = vector.new(pos)
  77. local name = minetest.get_node(p).name
  78. local d = 0
  79. while not papyrus.is_dirt_name(name) and d < papyrus.maxheight do
  80. -- All except bottom-most node must be plant.
  81. if name ~= papyrus.plantname then
  82. return
  83. end
  84. p.y = p.y - 1
  85. d = d + 1
  86. name = minetest.get_node(p).name
  87. end
  88. -- Must be on dirt or grass.
  89. if papyrus.is_dirt_name(name) then
  90. local meta = minetest.get_meta(p)
  91. local maxh = papyrus.random_height()
  92. meta:set_int("papyrus_height", maxh)
  93. meta:mark_as_private("papyrus_height")
  94. else
  95. return
  96. end
  97. -- Restart timer for plant directly above soil.
  98. p.y = p.y + 1
  99. if minetest.get_node(p).name ~= papyrus.plantname then
  100. return
  101. end
  102. local min = papyrus.steptime.min
  103. local max = papyrus.steptime.max
  104. minetest.get_node_timer(p):start(math_random(min, max))
  105. end
  106. -- Attempt to grow papyrus.
  107. -- Return 0 means nothing to report.
  108. -- 10 means plant has reached max height.
  109. function papyrus.grow(pos, node)
  110. -- Check if we can grow.
  111. if not papyrus.can_grow(pos) then
  112. return 0
  113. end
  114. if minetest.find_node_near(pos, 2, "group:cold") then
  115. return 12
  116. end
  117. -- Get how high we can grow.
  118. local maxh = papyrus.get_grow_height(pos)
  119. -- Find current height of plant.
  120. local height = 0
  121. while node.name == papyrus.plantname and height < maxh do
  122. height = height + 1
  123. pos.y = pos.y + 1
  124. node = minetest.get_node(pos)
  125. end
  126. if height >= maxh then
  127. -- Plant has reached max height.
  128. return 10
  129. end
  130. -- Check if we have room to grow some more.
  131. if node.name ~= "air" then
  132. return 0
  133. end
  134. -- Check if we have enough light.
  135. if minetest.get_node_light(pos) < papyrus.minlight then
  136. return 0
  137. end
  138. -- Grow!
  139. minetest.add_node(pos, {name = papyrus.plantname})
  140. return 0
  141. end
  142. function papyrus.on_construct(pos)
  143. -- Only the ground-level plant piece should have nodetimer.
  144. -- If plant is not placed on soil, it will never have nodetimer.
  145. if papyrus.has_dirt(pos) then
  146. local min = papyrus.steptime.min
  147. local max = papyrus.steptime.max
  148. minetest.get_node_timer(pos):start(math_random(min, max))
  149. end
  150. end
  151. function papyrus.on_destruct(pos)
  152. papyrus.reset_grow_height_and_timer(pos)
  153. end
  154. function papyrus.on_timer(pos, elapsed)
  155. --minetest.chat_send_all("# Server: Plant timer @ " .. minetest.pos_to_string(pos) .. "!")
  156. local node = minetest.get_node(pos)
  157. local result = papyrus.grow(pos, node)
  158. -- Plant has reached max height.
  159. if result == 10 then return end
  160. -- Plant cannot grow because of ice.
  161. if result == 12 then return end
  162. return true
  163. end
  164. function papyrus.after_dig_node(pos, node, metadata, digger)
  165. default.dig_up(pos, node, digger)
  166. -- No return value.
  167. end
  168. function papyrus.after_dig_node_hanging(pos, node, metadata, digger)
  169. default.dig_down(pos, node, digger)
  170. -- No return value.
  171. end
  172. if not papyrus.run_once then
  173. local c = "papyrus:core"
  174. local f = papyrus.modpath .. "/papyrus.lua"
  175. reload.register_file(c, f, false)
  176. papyrus.run_once = true
  177. end