More trees!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
10KB

  1. local S = moretrees.intllib
  2. -- © 2016, Rogier <rogier777@gmail.com>
  3. -- Some constants
  4. local coconut_drop_ichance = 8
  5. -- Make the cocos palm fruit trunk a real trunk (it is generated as a fruit)
  6. local trunk = minetest.registered_nodes["moretrees:palm_trunk"]
  7. local ftrunk = {}
  8. local gftrunk = {}
  9. for k,v in pairs(trunk) do
  10. ftrunk[k] = v
  11. gftrunk[k] = v
  12. end
  13. ftrunk.tiles = {}
  14. gftrunk.tiles = {}
  15. for k,v in pairs(trunk.tiles) do
  16. ftrunk.tiles[k] = v
  17. gftrunk.tiles[k] = v
  18. end
  19. ftrunk.drop = "moretrees:palm_trunk"
  20. gftrunk.drop = "moretrees:palm_trunk"
  21. ftrunk.after_destruct = function(pos, oldnode)
  22. local coconuts = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, {"group:moretrees_coconut"})
  23. for _,coconutpos in pairs(coconuts) do
  24. -- minetest.dig_node(coconutpos) does not cause nearby coconuts to be dropped :-( ...
  25. --minetest.dig_node(coconutpos)
  26. local items = minetest.get_node_drops(minetest.get_node(coconutpos).name)
  27. minetest.swap_node(coconutpos, biome_lib.air)
  28. for _, itemname in pairs(items) do
  29. minetest.add_item(coconutpos, itemname)
  30. end
  31. end
  32. end
  33. -- Make the different trunk types distinguishable (but barely)
  34. ftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR90"
  35. gftrunk.tiles[1] = "moretrees_palm_trunk_top.png^[transformR180"
  36. gftrunk.description = gftrunk.description.." (gen)"
  37. minetest.register_node("moretrees:palm_fruit_trunk", ftrunk)
  38. minetest.register_node("moretrees:palm_fruit_trunk_gen", gftrunk)
  39. local coconut_regrow_abm_spec = {
  40. nodenames = { "moretrees:palm_fruit_trunk" },
  41. interval = moretrees.coconut_flower_interval,
  42. chance = moretrees.coconut_flower_chance,
  43. action = function(pos, node, active_object_count, active_object_count_wider)
  44. local coconuts = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "group:moretrees_coconut")
  45. -- Expected growth interval increases exponentially with number of coconuts already hanging.
  46. -- Also: if more coconuts are hanging, the chance of picking an empty spot decreases as well...
  47. if math.random(2^#coconuts) <= 2 then
  48. -- Grow in area of 3x3 round trunk
  49. local dx=math.floor(math.random(3)-2)
  50. local dz=math.floor(math.random(3)-2)
  51. local coconutpos = {x=pos.x+dx, y=pos.y, z=pos.z+dz}
  52. local coconutnode = minetest.get_node(coconutpos)
  53. if coconutnode.name == "air" then
  54. minetest.swap_node(coconutpos, {name="moretrees:coconut_0"})
  55. end
  56. end
  57. end
  58. }
  59. if moretrees.coconuts_regrow then
  60. minetest.register_abm(coconut_regrow_abm_spec)
  61. end
  62. -- Spawn initial coconuts
  63. -- Spawn initial coconuts
  64. -- (Instead of coconuts, a generated-palm fruit trunk is generated with the tree. This
  65. -- ABM converts the trunk to a regular fruit trunk, and spawns some coconuts)
  66. minetest.register_abm({
  67. nodenames = { "moretrees:palm_fruit_trunk_gen" },
  68. interval = 1,
  69. chance = 1,
  70. action = function(pos, node, active_object_count, active_object_count_wider)
  71. minetest.swap_node(pos, {name="moretrees:palm_fruit_trunk"})
  72. local poslist = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "air")
  73. local genlist = {}
  74. for k,v in pairs(poslist) do
  75. genlist[k] = {x = math.random(100), pos = v}
  76. end
  77. table.sort(genlist, function(a, b) return a.x < b.x; end)
  78. local gen
  79. local count = 0
  80. for _,gen in pairs(genlist) do
  81. minetest.swap_node(gen.pos, {name = "moretrees:coconut_3"})
  82. count = count + 1
  83. if count == 4 then
  84. break
  85. end
  86. end
  87. end,
  88. })
  89. -- Register coconuts, and make them regrow
  90. local coconut_growfn = function(pos, elapsed)
  91. local node = minetest.get_node(pos)
  92. local delay = moretrees.coconut_grow_interval
  93. if not node then
  94. return
  95. elseif not moretrees.coconuts_regrow then
  96. -- Regrowing has been turned off. Make coconust grow instantly
  97. minetest.swap_node(pos, {name="moretrees:coconut_3"})
  98. return
  99. elseif node.name == "moretrees:coconut_3" then
  100. -- Drop coconuts (i.e. remove them), so that new coconuts can grow.
  101. -- Coconuts will drop as items with a small chance
  102. if math.random(coconut_drop_ichance) == 1 then
  103. if moretrees.coconut_item_drop_ichance > 0 and math.random(moretrees.coconut_item_drop_ichance) == 1 then
  104. local items = minetest.get_node_drops(minetest.get_node(pos).name)
  105. for _, itemname in pairs(items) do
  106. minetest.add_item(pos, itemname)
  107. end
  108. end
  109. minetest.swap_node(pos, biome_lib.air)
  110. end
  111. else
  112. -- Grow coconuts to the next stage
  113. local offset = string.len("moretrees:coconut_x")
  114. local n = string.sub(node.name, offset)
  115. minetest.swap_node(pos, {name=string.sub(node.name, 1, offset-1)..n+1})
  116. end
  117. -- Don't catch up when elapsed time is large. Regular visits are needed for growth...
  118. local timer = minetest.get_node_timer(pos)
  119. timer:start(delay + math.random(moretrees.coconut_grow_interval))
  120. end
  121. local coconut_starttimer = function(pos, elapsed)
  122. local timer = minetest.get_node_timer(pos)
  123. local base_interval = moretrees.coconut_grow_interval * 2 / 3
  124. timer:set(base_interval + math.random(base_interval), elapsed or 0)
  125. end
  126. for _,suffix in ipairs({"_0", "_1", "_2", "_3", ""}) do
  127. local name
  128. if suffix == "_0" then
  129. name = S("Coconut Flower")
  130. else
  131. name = S("Coconut")
  132. end
  133. local drop = ""
  134. local coco_group = 1
  135. local tile = "moretrees_coconut"..suffix..".png"
  136. local timerfn = coconut_growfn
  137. local constructfn = coconut_starttimer
  138. if suffix == "_3" then
  139. drop = "moretrees:coconut"
  140. tile = "moretrees_coconut.png"
  141. elseif suffix == "" then
  142. drop = nil
  143. coco_group = nil
  144. timerfn = nil
  145. constructfn = nil
  146. end
  147. local coconutdef = {
  148. description = name,
  149. tiles = {tile},
  150. drawtype = "plantlike",
  151. paramtype = "light",
  152. sunlight_propagates = true,
  153. walkable = false,
  154. groups = { fleshy=3, dig_immediate=3, flammable=2, moretrees_coconut=coco_group },
  155. inventory_image = tile.."^[transformR180",
  156. wield_image = tile.."^[transformR180",
  157. sounds = default.node_sound_defaults(),
  158. drop = drop,
  159. selection_box = {
  160. type = "fixed",
  161. fixed = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}
  162. },
  163. on_timer = timerfn,
  164. on_construct = constructfn,
  165. }
  166. minetest.register_node("moretrees:coconut"..suffix, coconutdef)
  167. end
  168. -- convert exisiting cocos palms. This is a bit tricky...
  169. -- Try to make sure that this is indeed a generated tree, and not manually-placed trunks and/or coconuts
  170. if moretrees.coconuts_convert_existing_palms then
  171. local spec = {
  172. name = "moretrees:convert_existing_cocos_palms_to_regrow_coconuts",
  173. nodenames = "moretrees:coconut",
  174. action = function(pos, node, active_object_count, active_object_count_wider)
  175. local trunks
  176. local cvtrunks
  177. local leaves
  178. local coconuts
  179. -- One regular trunk must be adjacent to the coconut
  180. trunks = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "moretrees:palm_trunk")
  181. if #trunks ~= 1 then
  182. return
  183. end
  184. local tpos = trunks[1]
  185. -- 1 or 2 other trunks must be one level below to the trunk being converted.
  186. trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y-1, z=tpos.z+1}, "moretrees:palm_trunk")
  187. if #trunks < 1 or #trunks > 2 then
  188. return
  189. end
  190. -- 1 or 2 other trunks must be two levels below to the trunk being converted.
  191. trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y-2, z=tpos.z+1}, "moretrees:palm_trunk")
  192. if #trunks < 1 or #trunks > 2 then
  193. return
  194. end
  195. -- 1 or 2 trunks must at the level of the trunk being converted.
  196. cvtrunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:palm_trunk")
  197. if #cvtrunks < 1 or #cvtrunks > 2 then
  198. return
  199. end
  200. -- No trunks may be one level above the trunk being converted.
  201. trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+1, z=tpos.z+1}, "moretrees:palm_trunk")
  202. if #trunks ~= 0 then
  203. return
  204. end
  205. -- Leaves must be one level above the trunk being converted.
  206. leaves = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+1, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+1, z=tpos.z+1}, "moretrees:palm_leaves")
  207. if #leaves == 0 then
  208. return
  209. end
  210. -- Leaves must be two levels above the trunk being converted.
  211. leaves = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y+2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y+2, z=tpos.z+1}, "moretrees:palm_leaves")
  212. if #leaves == 0 then
  213. return
  214. end
  215. -- No cocos fruit trunk may already be adjacent to the coconut
  216. trunks = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y, z=pos.z-1}, {x=pos.x+1, y=pos.y, z=pos.z+1}, "moretrees:palm_fruit_trunk")
  217. if #trunks ~= 0 then
  218. return
  219. end
  220. -- No cocos fruit trunk may be adjacent to or below the trunk being converted.
  221. trunks = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y-2, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:palm_fruit_trunk")
  222. if #trunks ~= 0 then
  223. return
  224. end
  225. -- Convert trunk and all coconuts nearby. Maybe convert 2 trunks, just in case...
  226. for _, tpos in pairs(cvtrunks) do
  227. minetest.swap_node(tpos, {name = "moretrees:palm_fruit_trunk"})
  228. coconuts = minetest.find_nodes_in_area({x=tpos.x-1, y=tpos.y, z=tpos.z-1}, {x=tpos.x+1, y=tpos.y, z=tpos.z+1}, "moretrees:coconut")
  229. for _, coconutpos in pairs(coconuts) do
  230. minetest.swap_node(coconutpos, {name = "moretrees:coconut_3"})
  231. end
  232. end
  233. end,
  234. }
  235. if minetest.register_lbm then
  236. minetest.register_lbm(spec)
  237. else
  238. spec.interval = 3691
  239. spec.chance = 10
  240. minetest.register_abm(spec)
  241. end
  242. end
  243. -- If regrowing was previously disabled, but is enabled now, make sure timers are started for existing coconuts
  244. if moretrees.coconuts_regrow then
  245. local spec = {
  246. name = "moretrees:restart_coconut_regrow_timer",
  247. nodenames = "group:moretrees_coconut",
  248. action = function(pos, node, active_object_count, active_object_count_wider)
  249. local timer = minetest.get_node_timer(pos)
  250. if not timer:is_started() then
  251. coconut_starttimer(pos)
  252. else
  253. local timeout = timer:get_timeout()
  254. local elapsed = timer:get_elapsed()
  255. if timeout - elapsed > moretrees.coconut_grow_interval * 4/3 then
  256. coconut_starttimer(pos, math.random(moretrees.coconut_grow_interval * 4/3))
  257. end
  258. end
  259. end,
  260. }
  261. if minetest.register_lbm then
  262. minetest.register_lbm(spec)
  263. else
  264. spec.interval = 3659
  265. spec.chance = 10
  266. minetest.register_abm(spec)
  267. end
  268. end