cocos_palm.lua 10 KB

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