Adds mulch, bonemeal and fertilizer to Minetest to quick grow crops and saplings https://content.minetest.net/packages/TenPlus1/bonemeal/
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.

663 lines
14KB

  1. bonemeal = {}
  2. local path = minetest.get_modpath("bonemeal")
  3. local min, max, random = math.min, math.max, math.random
  4. -- Load support for intllib.
  5. local S, NS = dofile(path .. "/intllib.lua")
  6. -- creative check
  7. local creative_mode_cache = minetest.settings:get_bool("creative_mode")
  8. function is_creative(name)
  9. return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
  10. end
  11. -- default crops
  12. local crops = {
  13. {"farming:cotton_", 8, "farming:seed_cotton"},
  14. {"farming:wheat_", 8, "farming:seed_wheat"}
  15. }
  16. -- special pine check for nearby snow
  17. local function pine_grow(pos)
  18. if minetest.find_node_near(pos, 1,
  19. {"default:snow", "default:snowblock", "default:dirt_with_snow"}) then
  20. default.grow_new_snowy_pine_tree(pos)
  21. else
  22. default.grow_new_pine_tree(pos)
  23. end
  24. end
  25. -- default saplings
  26. local saplings = {
  27. {"default:sapling", default.grow_new_apple_tree, "soil"},
  28. {"default:junglesapling", default.grow_new_jungle_tree, "soil"},
  29. {"default:emergent_jungle_sapling", default.grow_new_emergent_jungle_tree, "soil"},
  30. {"default:acacia_sapling", default.grow_new_acacia_tree, "soil"},
  31. {"default:aspen_sapling", default.grow_new_aspen_tree, "soil"},
  32. {"default:pine_sapling", pine_grow, "soil"},
  33. {"default:bush_sapling", default.grow_bush, "soil"},
  34. {"default:acacia_bush_sapling", default.grow_acacia_bush, "soil"},
  35. {"default:large_cactus_seedling", default.grow_large_cactus, "sand"},
  36. {"default:blueberry_bush_sapling", default.grow_blueberry_bush, "soil"},
  37. {"default:pine_bush_sapling", default.grow_pine_bush, "soil"}
  38. }
  39. -- helper tables ( "" denotes a blank item )
  40. local green_grass = {
  41. "default:grass_2", "default:grass_3", "default:grass_4",
  42. "default:grass_5", "", ""
  43. }
  44. local dry_grass = {
  45. "default:dry_grass_2", "default:dry_grass_3", "default:dry_grass_4",
  46. "default:dry_grass_5", "", ""
  47. }
  48. -- add all in-game flowers except waterlily
  49. local flowers = {}
  50. for node, def in pairs(minetest.registered_nodes) do
  51. if def.groups.flower and not node:find("waterlily") then
  52. flowers[#flowers + 1] = node
  53. end
  54. end
  55. -- add additional bakedclay flowers if enabled
  56. if minetest.get_modpath("bakedclay") then
  57. flowers[#flowers + 1] = "bakedclay:delphinium"
  58. flowers[#flowers + 1] = "bakedclay:thistle"
  59. flowers[#flowers + 1] = "bakedclay:lazarus"
  60. flowers[#flowers + 1] = "bakedclay:mannagrass"
  61. flowers[#flowers + 1] = ""
  62. end
  63. -- default biomes deco
  64. local deco = {
  65. {"default:dirt_with_dry_grass", dry_grass, flowers},
  66. {"default:sand", {}, {"default:dry_shrub", "", "", ""} },
  67. {"default:desert_sand", {}, {"default:dry_shrub", "", "", ""} },
  68. {"default:silver_sand", {}, {"default:dry_shrub", "", "", ""} },
  69. }
  70. --
  71. -- local functions
  72. --
  73. -- particles
  74. local function particle_effect(pos)
  75. minetest.add_particlespawner({
  76. amount = 4,
  77. time = 0.15,
  78. minpos = pos,
  79. maxpos = pos,
  80. minvel = {x = -1, y = 2, z = -1},
  81. maxvel = {x = 1, y = 4, z = 1},
  82. minacc = {x = -1, y = -1, z = -1},
  83. maxacc = {x = 1, y = 1, z = 1},
  84. minexptime = 1,
  85. maxexptime = 1,
  86. minsize = 1,
  87. maxsize = 3,
  88. texture = "bonemeal_particle.png"
  89. })
  90. end
  91. -- tree type check
  92. local function grow_tree(pos, object)
  93. if type(object) == "table" and object.axiom then
  94. -- grow L-system tree
  95. minetest.remove_node(pos)
  96. minetest.spawn_tree(pos, object)
  97. elseif type(object) == "string" and minetest.registered_nodes[object] then
  98. -- place node
  99. minetest.set_node(pos, {name = object})
  100. elseif type(object) == "function" then
  101. -- function
  102. object(pos)
  103. end
  104. end
  105. -- sapling check
  106. local function check_sapling(pos, nodename)
  107. -- what is sapling placed on?
  108. local under = minetest.get_node({
  109. x = pos.x,
  110. y = pos.y - 1,
  111. z = pos.z
  112. })
  113. local can_grow, grow_on
  114. -- check list for sapling and function
  115. for n = 1, #saplings do
  116. if saplings[n][1] == nodename then
  117. grow_on = saplings[n][3]
  118. -- sapling grows on top of specific node
  119. if grow_on
  120. and grow_on ~= "soil"
  121. and grow_on ~= "sand"
  122. and grow_on == under.name then
  123. can_grow = true
  124. end
  125. -- sapling grows on top of soil (default)
  126. if can_grow == nil
  127. and (grow_on == nil or grow_on == "soil")
  128. and minetest.get_item_group(under.name, "soil") > 0 then
  129. can_grow = true
  130. end
  131. -- sapling grows on top of sand
  132. if can_grow == nil
  133. and grow_on == "sand"
  134. and minetest.get_item_group(under.name, "sand") > 0 then
  135. can_grow = true
  136. end
  137. -- check if we can grow sapling
  138. if can_grow then
  139. particle_effect(pos)
  140. grow_tree(pos, saplings[n][2])
  141. return
  142. end
  143. end
  144. end
  145. end
  146. -- crops check
  147. local function check_crops(pos, nodename, strength)
  148. local mod, crop, stage, nod, def
  149. -- grow registered crops
  150. for n = 1, #crops do
  151. if nodename:find(crops[n][1])
  152. or nodename == crops[n][3] then
  153. -- separate mod and node name
  154. mod = nodename:split(":")[1] .. ":"
  155. crop = nodename:split(":")[2]
  156. -- get stage number or set to 0 for seed
  157. stage = tonumber( crop:split("_")[2] ) or 0
  158. stage = min(stage + strength, crops[n][2])
  159. -- check for place_param setting
  160. nod = crops[n][1] .. stage
  161. def = minetest.registered_nodes[nod]
  162. def = def and def.place_param2 or 0
  163. minetest.set_node(pos, {name = nod, param2 = def})
  164. particle_effect(pos)
  165. return
  166. end
  167. end
  168. end
  169. -- check soil for specific decoration placement
  170. local function check_soil(pos, nodename, strength)
  171. -- set radius according to strength
  172. local side = strength - 1
  173. local tall = max(strength - 2, 0)
  174. local floor
  175. local groups = minetest.registered_items[nodename]
  176. and minetest.registered_items[nodename].groups or {}
  177. -- only place decoration on one type of surface
  178. if groups.soil then
  179. floor = {"group:soil"}
  180. elseif groups.sand then
  181. floor = {"group:sand"}
  182. else
  183. floor = {nodename}
  184. end
  185. -- get area of land with free space above
  186. local dirt = minetest.find_nodes_in_area_under_air(
  187. {x = pos.x - side, y = pos.y - tall, z = pos.z - side},
  188. {x = pos.x + side, y = pos.y + tall, z = pos.z + side}, floor)
  189. -- set default grass and decoration
  190. local grass = green_grass
  191. local decor = flowers
  192. -- choose grass and decoration to use on dirt patch
  193. for n = 1, #deco do
  194. -- do we have a grass match?
  195. if nodename == deco[n][1] then
  196. grass = deco[n][2] or {}
  197. decor = deco[n][3] or {}
  198. end
  199. end
  200. local pos2, nod, def
  201. -- loop through soil
  202. for _, n in pairs(dirt) do
  203. if random(5) == 5 then
  204. if decor and #decor > 0 then
  205. -- place random decoration (rare)
  206. local dnum = #decor or 1
  207. nod = decor[random(dnum)] or ""
  208. end
  209. else
  210. if grass and #grass > 0 then
  211. -- place random grass (common)
  212. local dgra = #grass or 1
  213. nod = #grass > 0 and grass[random(dgra)] or ""
  214. end
  215. end
  216. pos2 = n
  217. pos2.y = pos2.y + 1
  218. if nod and nod ~= "" then
  219. -- get crop param2 value
  220. def = minetest.registered_nodes[nod]
  221. def = def and def.place_param2
  222. -- if param2 not preset then get from existing node
  223. if not def then
  224. local node = minetest.get_node_or_nil(pos2)
  225. def = node and node.param2 or 0
  226. end
  227. minetest.set_node(pos2, {name = nod, param2 = def})
  228. end
  229. particle_effect(pos2)
  230. end
  231. end
  232. -- global functions
  233. -- add to sapling list
  234. -- {sapling node, schematic or function name, "soil"|"sand"|specific_node}
  235. --e.g. {"default:sapling", default.grow_new_apple_tree, "soil"}
  236. function bonemeal:add_sapling(list)
  237. for n = 1, #list do
  238. saplings[#saplings + 1] = list[n]
  239. end
  240. end
  241. -- add to crop list to force grow
  242. -- {crop name start_, growth steps, seed node (if required)}
  243. -- e.g. {"farming:wheat_", 8, "farming:seed_wheat"}
  244. function bonemeal:add_crop(list)
  245. for n = 1, #list do
  246. crops[#crops + 1] = list[n]
  247. end
  248. end
  249. -- add grass and flower/plant decoration for specific dirt types
  250. -- {dirt_node, {grass_nodes}, {flower_nodes}
  251. -- e.g. {"default:dirt_with_dry_grass", dry_grass, flowers}
  252. -- if an entry already exists for a given dirt type, it will add new entries and all empty
  253. -- entries, allowing to both add decorations and decrease their frequency.
  254. function bonemeal:add_deco(list)
  255. for l = 1, #list do
  256. for n = 1, #deco do
  257. -- update existing entry
  258. if list[l][1] == deco[n][1] then
  259. -- adding grass types
  260. for _, extra in pairs(list[l][2]) do
  261. if extra ~= "" then
  262. for _, entry in pairs(deco[n][2]) do
  263. if extra == entry then
  264. extra = false
  265. break
  266. end
  267. end
  268. end
  269. if extra then
  270. deco[n][2][#deco[n][2] + 1] = extra
  271. end
  272. end
  273. -- adding decoration types
  274. for _, extra in ipairs(list[l][3]) do
  275. if extra ~= "" then
  276. for __, entry in pairs(deco[n][3]) do
  277. if extra == entry then
  278. extra = false
  279. break
  280. end
  281. end
  282. end
  283. if extra then
  284. deco[n][3][#deco[n][3] + 1] = extra
  285. end
  286. end
  287. list[l] = false
  288. break
  289. end
  290. end
  291. if list[l] then
  292. deco[#deco + 1] = list[l]
  293. end
  294. end
  295. end
  296. -- definitively set a decration scheme
  297. -- this function will either add a new entry as is, or replace the existing one
  298. function bonemeal:set_deco(list)
  299. for l = 1, #list do
  300. for n = 1, #deco do
  301. -- replace existing entry
  302. if list[l][1] == deco[n][1] then
  303. deco[n][2] = list[l][2]
  304. deco[n][3] = list[l][3]
  305. list[l] = false
  306. break
  307. end
  308. end
  309. if list[l] then
  310. deco[#deco + 1] = list[l]
  311. end
  312. end
  313. end
  314. -- global on_use function for bonemeal
  315. function bonemeal:on_use(pos, strength, node)
  316. -- get node pointed at
  317. local node = node or minetest.get_node(pos)
  318. -- return if nothing there
  319. if node.name == "ignore" then
  320. return
  321. end
  322. -- make sure strength is between 1 and 4
  323. strength = strength or 1
  324. strength = max(strength, 1)
  325. strength = min(strength, 4)
  326. -- papyrus and cactus
  327. if node.name == "default:papyrus" then
  328. default.grow_papyrus(pos, node)
  329. particle_effect(pos)
  330. return
  331. elseif node.name == "default:cactus" then
  332. default.grow_cactus(pos, node)
  333. particle_effect(pos)
  334. return
  335. end
  336. -- grow grass and flowers
  337. if minetest.get_item_group(node.name, "soil") > 0
  338. or minetest.get_item_group(node.name, "sand") > 0
  339. or minetest.get_item_group(node.name, "can_bonemeal") > 0 then
  340. check_soil(pos, node.name, strength)
  341. return
  342. end
  343. -- light check depending on strength (strength of 4 = no light needed)
  344. if (minetest.get_node_light(pos) or 0) < (12 - (strength * 3)) then
  345. return
  346. end
  347. -- check for tree growth if pointing at sapling
  348. -- if minetest.get_item_group(node.name, "sapling") > 0
  349. if random(5 - strength) == 1 then
  350. check_sapling(pos, node.name)
  351. return
  352. end
  353. -- check for crop growth
  354. check_crops(pos, node.name, strength)
  355. end
  356. --
  357. -- items
  358. --
  359. -- mulch (strength 1)
  360. minetest.register_craftitem("bonemeal:mulch", {
  361. description = S("Mulch"),
  362. inventory_image = "bonemeal_mulch.png",
  363. on_use = function(itemstack, user, pointed_thing)
  364. -- did we point at a node?
  365. if pointed_thing.type ~= "node" then
  366. return
  367. end
  368. -- is area protected?
  369. if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
  370. return
  371. end
  372. -- take item if not in creative
  373. if not is_creative(user:get_player_name()) then
  374. itemstack:take_item()
  375. end
  376. -- call global on_use function with strength of 1
  377. bonemeal:on_use(pointed_thing.under, 1)
  378. return itemstack
  379. end
  380. })
  381. -- bonemeal (strength 2)
  382. minetest.register_craftitem("bonemeal:bonemeal", {
  383. description = S("Bone Meal"),
  384. inventory_image = "bonemeal_item.png",
  385. on_use = function(itemstack, user, pointed_thing)
  386. -- did we point at a node?
  387. if pointed_thing.type ~= "node" then
  388. return
  389. end
  390. -- is area protected?
  391. if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
  392. return
  393. end
  394. -- take item if not in creative
  395. if not is_creative(user:get_player_name()) then
  396. itemstack:take_item()
  397. end
  398. -- call global on_use function with strength of 2
  399. bonemeal:on_use(pointed_thing.under, 2)
  400. return itemstack
  401. end
  402. })
  403. -- fertiliser (strength 3)
  404. minetest.register_craftitem("bonemeal:fertiliser", {
  405. description = S("Fertiliser"),
  406. inventory_image = "bonemeal_fertiliser.png",
  407. on_use = function(itemstack, user, pointed_thing)
  408. -- did we point at a node?
  409. if pointed_thing.type ~= "node" then
  410. return
  411. end
  412. -- is area protected?
  413. if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
  414. return
  415. end
  416. -- take item if not in creative
  417. if not is_creative(user:get_player_name()) then
  418. itemstack:take_item()
  419. end
  420. -- call global on_use function with strength of 3
  421. bonemeal:on_use(pointed_thing.under, 3)
  422. return itemstack
  423. end
  424. })
  425. -- bone
  426. minetest.register_craftitem("bonemeal:bone", {
  427. description = S("Bone"),
  428. inventory_image = "bonemeal_bone.png"
  429. })
  430. -- gelatin powder
  431. minetest.register_craftitem("bonemeal:gelatin_powder", {
  432. description = S("Gelatin Powder"),
  433. inventory_image = "bonemeal_gelatin_powder.png",
  434. groups = {food_gelatin = 1, flammable = 2}
  435. })
  436. --
  437. -- crafting recipes
  438. --
  439. -- gelatin powder
  440. minetest.register_craft({
  441. output = "bonemeal:gelatin_powder 4",
  442. recipe = {
  443. {"bonemeal:bone", "bonemeal:bone", "bonemeal:bone"},
  444. {"bucket:bucket_water", "bucket:bucket_water", "bucket:bucket_water"},
  445. {"bucket:bucket_water", "default:torch", "bucket:bucket_water"},
  446. },
  447. replacements = {
  448. {"bucket:bucket_water", "bucket:bucket_empty 5"},
  449. }
  450. })
  451. -- bonemeal (from bone)
  452. minetest.register_craft({
  453. type = "shapeless",
  454. output = "bonemeal:bonemeal 2",
  455. recipe = {"bonemeal:bone"}
  456. })
  457. -- bonemeal (from player bones)
  458. minetest.register_craft({
  459. type = "shapeless",
  460. output = "bonemeal:bonemeal 4",
  461. recipe = {"bones:bones"}
  462. })
  463. -- bonemeal (from coral skeleton)
  464. minetest.register_craft({
  465. type = "shapeless",
  466. output = "bonemeal:bonemeal 2",
  467. recipe = {"default:coral_skeleton"}
  468. })
  469. -- mulch
  470. minetest.register_craft({
  471. type = "shapeless",
  472. output = "bonemeal:mulch 4",
  473. recipe = {
  474. "group:tree", "group:leaves", "group:leaves",
  475. "group:leaves", "group:leaves", "group:leaves",
  476. "group:leaves", "group:leaves", "group:leaves"
  477. }
  478. })
  479. -- fertiliser
  480. minetest.register_craft({
  481. type = "shapeless",
  482. output = "bonemeal:fertiliser 2",
  483. recipe = {"bonemeal:bonemeal", "bonemeal:mulch"}
  484. })
  485. -- add bones to dirt
  486. minetest.override_item("default:dirt", {
  487. drop = {
  488. max_items = 1,
  489. items = {
  490. {
  491. items = {"bonemeal:bone"},
  492. rarity = 30
  493. },
  494. {
  495. items = {"default:dirt"}
  496. }
  497. }
  498. }
  499. })
  500. -- add support for other mods
  501. dofile(path .. "/mods.lua")
  502. dofile(path .. "/lucky_block.lua")
  503. print (S("[MOD] bonemeal loaded"))