init.lua 14 KB

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