init.lua 16 KB

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