seeder.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. --*******************************************************
  2. --**** The Seeder
  3. --**** All coding made by Gundul except recursive_dig
  4. --**** was taken from technic:chainsaw mod coded by
  5. --**** Maciej Kasatkin (RealBadAngel)
  6. --*******************************************************
  7. local farm_redo = false
  8. local S = farmingNG.S
  9. -- different values if technic not present
  10. if not farmingNG.havetech then
  11. farmingNG.seeder_charge_per_node = math.floor(65535 / farmingNG.seeder_max_charge * farmingNG.seeder_charge_per_node)
  12. farmingNG.seeder_max_charge = 65535
  13. end
  14. --check for farming redo mod
  15. if minetest.global_exists("farming") then
  16. if farming.mod == "redo" then farm_redo = true end
  17. end
  18. -- grapes and beans from farming_plus need helpers to grow
  19. if minetest.get_modpath("farming_plus") or farm_redo then
  20. minetest.register_craftitem("farming_nextgen:grape_seedling", {
  21. description = S("A grape seedling for the seeder"),
  22. inventory_image = "farming_grapes_1.png"
  23. })
  24. minetest.register_craftitem("farming_nextgen:bean_seedling", {
  25. description = S("A bean seedling for the seeder"),
  26. inventory_image = "farming_beanpole_1.png"
  27. })
  28. if not farm_redo then
  29. minetest.register_craft({
  30. type = "shapeless",
  31. output = "farming_nextgen:grape_seedling",
  32. recipe = {"farming_plus:trellis","farming_plus:grapes"}
  33. })
  34. minetest.register_craft({
  35. type = "shapeless",
  36. output = "farming_nextgen:bean_seedling",
  37. recipe = {"farming_plus:beanpole","farming_plus:beans"}
  38. })
  39. else
  40. minetest.register_craft({
  41. type = "shapeless",
  42. output = "farming_nextgen:grape_seedling",
  43. recipe = {"farming:trellis","farming:grapes"}
  44. })
  45. minetest.register_craft({
  46. type = "shapeless",
  47. output = "farming_nextgen:bean_seedling",
  48. recipe = {"farming:beanpole","farming:beans"}
  49. })
  50. end
  51. end
  52. -- The default soils
  53. local soil_nodenames = {
  54. ["farming:soil"] = true,
  55. ["farming:soil_wet"] = true,
  56. ["farming:desert_sand_soil"] = true,
  57. ["farming:desert_sand_soil_wet"]= true,
  58. ["farming:dry_soil"] = true,
  59. ["farming:dry_soil_wet"] = true
  60. }
  61. --support compost mod
  62. if minetest.get_modpath("compost") then
  63. soil_nodenames["compost:garden_soil"] = true
  64. end
  65. farmingNG.seeder_seed = {
  66. -- *** farming
  67. {"farming:seed_barley", "farming:barley_1"},
  68. {"farming:seed_hemp", "farming:hemp_1"},
  69. {"farming:pumpkin_seed", "farming:pumpkin_1"},
  70. {"farming:coffee_beans", "farming:coffee_1"},
  71. {"farming:chili_pepper", "farming:chili_1"},
  72. {"farming:carrot", "farming:carrot_1"},
  73. {"farming:corn", "farming:corn_1"},
  74. {"farming:cucumber", "farming:cucumber_1"},
  75. {"farming:garlic_clove", "farming:garlic_1"},
  76. {"farming:melon_slice", "farming:melon_1"},
  77. {"farming:onion", "farming:onion_1"},
  78. {"farming:peppercorn", "farming:pepper_1"},
  79. {"farming:pineapple_top", "farming:pineapple_1"},
  80. {"farming:potato", "farming:potato_1"},
  81. {"farming:pumpkin_slice", "farming:pumpkin_1"},
  82. {"farming:raspberries", "farming:raspberry_1"},
  83. {"farming:rhubarb", "farming:rhubarb_1"},
  84. {"farming:tomato", "farming:tomato_1"},
  85. {"farming:blueberries", "farming:blueberry_1"},
  86. {"farming:pea_pod", "farming:pea_1"},
  87. {"farming:beetroot", "farming:beetroot_1"},
  88. {"farming:seed_rice", "farming:rice_1"},
  89. {"farming:seed_oat", "farming:oat_1"},
  90. {"farming:seed_rye", "farming:rye_1"},
  91. {"farming:cabbage", "farming:cabbage_1"},
  92. {"farming:seed_mint", "farming:mint_1"},
  93. -- *** farming_plus
  94. {"farming_plus:carrot_seed", "farming_plus:carrot_1"},
  95. {"farming_plus:chilli_seeds", "farming_plus:chilli_1"},
  96. {"farming_plus:coffee_beans", "farming_plus:coffee_1"},
  97. {"farming_plus:corn_seed", "farming_plus:corn_1"},
  98. {"farming_plus:cucumber_seed", "farming_plus:cucumber_1"},
  99. {"farming_plus:garlic_seed", "farming_plus:garlic_1"},
  100. {"farming_plus:seed_hemp", "farming_plus:hemp_1"},
  101. {"farming_plus:melon_seed", "farming_plus:melon_1"},
  102. {"farming_plus:potato_seed", "farming_plus:potato_1"},
  103. {"farming_plus:rhubarb_seed", "farming_plus:rhubarb_1"},
  104. {"farming_plus:raspberry_seed", "farming_plus:raspberry_1"},
  105. {"farming_plus:strawberry_seed", "farming_plus:strawberry_1"},
  106. {"farming_plus:soy_seed", "farming_plus:soy_plant_1"},
  107. {"farming_plus:tomato_seed", "farming_plus:tomato_1"},
  108. {"farming_plus:walnut_item", "farming_plus:walnut_1"},
  109. {"farming_plus:orange_seed", "farming_plus:orange_1"},
  110. {"farming_plus:lemon_seed", "farming_plus:lemon_1"},
  111. {"farming_plus:peach_seed", "farming_plus:peach_1"},
  112. {"farming_plus:seed_barley", "farming_plus:barley_1"},
  113. {"farming_plus:coffee_beans", "farming_plus:coffee_1"},
  114. -- *** beer_test
  115. {"beer_test:seed_oats", "beer_test:seed_oats"},
  116. -- If you have Problems with growing wheat and cotton, then try the two lines below
  117. {"farming:seed_wheat", "farming:wheat_1"},
  118. {"farming:seed_cotton", "farming:cotton_1"}
  119. -- If you haven't any Problems with growing wheat and cotton, then use the two lines below
  120. -- {"farming:seed_wheat", "farming:seed_wheat"},
  121. -- {"farming:seed_cotton", "farming:seed_cotton"}
  122. }
  123. -- wine and beans need climbing utilities
  124. farmingNG.seeder_utils = {
  125. {"farming_nextgen:grape_seedling", "farming_plus:grapes_1"},
  126. {"farming_nextgen:bean_seedling", "farming_plus:beanpole_1"}
  127. }
  128. if farm_redo then
  129. farmingNG.seeder_utils = {
  130. {"farming_nextgen:grape_seedling", "farming:grapes_1"},
  131. {"farming_nextgen:bean_seedling", "farming:beanpole_1"}
  132. }
  133. end
  134. local function check_valid_util(sname)
  135. for i in ipairs(farmingNG.seeder_utils) do
  136. if sname == farmingNG.seeder_utils[i][1] then return true end
  137. end
  138. return false
  139. end
  140. -- function to check for valid seeds
  141. local function check_valid_seed(sname)
  142. for i in ipairs(farmingNG.seeder_seed) do
  143. if sname == farmingNG.seeder_seed[i][1] then return true end
  144. end
  145. return false
  146. end
  147. --function to give name of seedlings
  148. local function give_seedling(sname, util)
  149. if not util then
  150. for i in ipairs(farmingNG.seeder_seed) do
  151. if sname == farmingNG.seeder_seed[i][1] then return farmingNG.seeder_seed[i][2] end
  152. end
  153. else
  154. for i in ipairs(farmingNG.seeder_utils) do
  155. if sname ==farmingNG.seeder_utils[i][1] then return farmingNG.seeder_utils[i][2] end
  156. end
  157. end
  158. return nil
  159. end
  160. --- Iterator over positions to try to saw around a sawed node.
  161. -- This returns positions in a 3x1x3 area around the position, plus the
  162. -- position above it. This does not return the bottom position to prevent
  163. -- the seeder from cutting down nodes below the cutting position.
  164. -- @param pos Sawing position.
  165. function farmingNG.iterSawTries(pos)
  166. -- Copy position to prevent mangling it
  167. local pos = vector.new(pos)
  168. local i = 0
  169. return function()
  170. i = i + 1
  171. -- Given a (top view) area like so (where 5 is the starting position):
  172. -- X -->
  173. -- Z 123
  174. -- | 456
  175. -- V 789
  176. -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9,
  177. -- and the position above 5.
  178. if i == 1 then
  179. -- Move to starting position
  180. pos.x = pos.x - 1
  181. pos.z = pos.z - 1
  182. elseif i == 4 or i == 7 then
  183. -- Move to next X and back to start of Z when we reach
  184. -- the end of a Z line.
  185. pos.x = pos.x + 1
  186. pos.z = pos.z - 2
  187. elseif i == 5 then
  188. -- Skip the middle position (we've already run on it)
  189. -- and double-increment the counter.
  190. pos.z = pos.z + 2
  191. i = i + 1
  192. elseif i <= 9 then
  193. -- Go to next Z.
  194. pos.z = pos.z + 1
  195. elseif i == 10 then
  196. -- Move back to center and up.
  197. -- The Y+ position must be last so that we don't dig
  198. -- straight upward and not come down (since the Y-
  199. -- position isn't checked).
  200. pos.x = pos.x - 1
  201. pos.z = pos.z - 1
  202. pos.y = pos.y + 1
  203. else
  204. return nil
  205. end
  206. return pos
  207. end
  208. end
  209. -- This function does all the hard work. Recursively we dig the node at hand
  210. -- if it is in the table and then search the surroundings for more stuff to dig.
  211. local function recursive_dig(pos, remaining_charge, seednum,seedstack, user)
  212. local uppos = {x =pos.x, y =(pos.y) +1,z =pos.z}
  213. local toppos = {x =pos.x, y =(pos.y) +2,z =pos.z}
  214. local name = user:get_player_name()
  215. if remaining_charge < farmingNG.seeder_charge_per_node or seedstack:is_empty() then
  216. return remaining_charge, seednum, seedstack
  217. end
  218. local node = minetest.get_node(pos)
  219. local upper = minetest.get_node(uppos)
  220. local top = minetest.get_node(toppos)
  221. local seedname = seedstack:get_name()
  222. local helpers = check_valid_util(upper.name)
  223. if node.name == "farming:weed" then
  224. remaining_charge, seednum, seedstack = recursive_dig( {x=pos.x, y=pos.y-1, z=pos.z}, remaining_charge, seednum, seedstack, user)
  225. return remaining_charge, seednum, seedstack
  226. end
  227. if not soil_nodenames[node.name] then
  228. return remaining_charge, seednum, seedstack
  229. end
  230. if not check_valid_util(seedname) then
  231. if upper.name == "air" or upper.name == "farming:weed" or string.match(upper.name,"default:grass")then
  232. minetest.set_node(uppos, {name="air"})
  233. remaining_charge = remaining_charge - farmingNG.seeder_charge_per_node
  234. seednum = seednum +1
  235. seedstack:take_item()
  236. if remaining_charge < 1 then remaining_charge = 1 end
  237. if give_seedling(seedname,false) then
  238. minetest.add_node(uppos, {name = give_seedling(seedname,false), param2 = 1})
  239. minetest.get_node_timer(uppos):start(math.random(166, 286))
  240. end
  241. else
  242. return remaining_charge, seednum, seedstack
  243. end
  244. else
  245. if (upper.name == "air" or upper.name == "farming:weed" or string.match(upper.name,"default:grass")) and top.name == "air" then
  246. minetest.set_node(uppos, {name="air"})
  247. remaining_charge = remaining_charge - farmingNG.seeder_charge_per_node
  248. seednum = seednum +1
  249. seedstack:take_item()
  250. if remaining_charge < 1 then remaining_charge = 1 end
  251. if give_seedling(seedname, true) then
  252. minetest.add_node(uppos, {name = give_seedling(seedname, true), param2 = 1})
  253. minetest.get_node_timer(uppos):start(math.random(166, 286))
  254. end
  255. else
  256. return remaining_charge, seednum, seedstack
  257. end
  258. end
  259. -- Check surroundings and run recursively if any charge left
  260. for npos in farmingNG.iterSawTries(pos) do
  261. if remaining_charge < farmingNG.seeder_charge_per_node then
  262. break
  263. end
  264. if soil_nodenames[minetest.get_node(npos).name] then
  265. remaining_charge, seednum, seedstack = recursive_dig(npos, remaining_charge, seednum, seedstack, user)
  266. end
  267. end
  268. return remaining_charge, seednum, seedstack
  269. end
  270. -- Seeder entry point
  271. local function seeder_dig(pos, current_charge, seednum, seedstack, user)
  272. -- Start sawing things down
  273. local remaining_charge, seednum, seedstack = recursive_dig(pos, current_charge, seednum, seedstack, user)
  274. minetest.sound_play("farming_nextgen_seeder", {pos = pos, gain = 0.1, max_hear_distance = 10})
  275. return remaining_charge, seednum, seedstack
  276. end
  277. if farmingNG.havetech then
  278. --local S = technic.getter
  279. technic.register_power_tool("farming_nextgen:seeder", farmingNG.seeder_max_charge)
  280. minetest.register_tool("farming_nextgen:seeder", {
  281. description = S("Seed Machine"),
  282. inventory_image = "farming_nextgen_seeder.png",
  283. stack_max = 1,
  284. wear_represents = "technic_RE_charge",
  285. on_refill = technic.refill_RE_charge,
  286. on_use = function(itemstack, user, pointed_thing)
  287. local seednum=0
  288. local name = user:get_player_name()
  289. local privs = minetest.get_player_privs(name)
  290. if pointed_thing.type ~= "node" then
  291. return itemstack
  292. end
  293. local meta = minetest.deserialize(itemstack:get_metadata())
  294. if not meta or not meta.charge or
  295. meta.charge < farmingNG.seeder_charge_per_node then
  296. return
  297. end
  298. local inv = user:get_inventory()
  299. local indexnumber = user:get_wield_index()+1
  300. local seedstack = inv:get_stack("main", indexnumber)
  301. local seedname = seedstack:get_name()
  302. if minetest.is_protected(pointed_thing.under, name) then
  303. minetest.record_protection_violation(pointed_thing.under, name)
  304. return
  305. end
  306. -- Send current charge to digging function so that the
  307. -- seeder will stop after digging a number of nodes
  308. if seedname then
  309. if check_valid_seed(seedname) or check_valid_util(seedname) then
  310. meta.charge, seednum, seedstack = seeder_dig(pointed_thing.under, meta.charge, seednum, seedstack, user)
  311. minetest.chat_send_player(name,S("*** You used : @1 seeds",seednum))
  312. else
  313. minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
  314. end
  315. else
  316. minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
  317. end
  318. if not technic.creative_mode then
  319. technic.set_RE_wear(itemstack, meta.charge, farmingNG.seeder_max_charge)
  320. itemstack:set_metadata(minetest.serialize(meta))
  321. end
  322. inv:set_stack("main", indexnumber, seedstack)
  323. return itemstack
  324. end,
  325. })
  326. local mesecons_button = minetest.get_modpath("mesecons_button")
  327. local trigger = mesecons_button and "mesecons_button:button_off" or "default:mese_crystal_fragment"
  328. if farmingNG.easy then
  329. minetest.register_craft({
  330. output = "farming_nextgen:seeder",
  331. recipe = {
  332. {"technic:battery", trigger, "technic:battery" },
  333. {"technic:stainless_steel_ingot", "technic:stainless_steel_ingot", "technic:stainless_steel_ingot"},
  334. {"default:diamond", "", "default:diamond"},
  335. }
  336. })
  337. else
  338. minetest.register_craft({
  339. output = "farming_nextgen:seeder",
  340. recipe = {
  341. {"technic:red_energy_crystal", trigger, "technic:red_energy_crystal" },
  342. {"technic:composite_plate", "technic:composite_plate", "technic:composite_plate"},
  343. {"technic:rubber", "", "technic:rubber"},
  344. }
  345. })
  346. end
  347. else
  348. minetest.register_tool("farming_nextgen:seeder", {
  349. description = S("Automatik seeding tool"),
  350. groups = {soil=3,soil=2},
  351. inventory_image = "farming_nextgen_seeder.png",
  352. stack_max=1,
  353. liquids_pointable = false,
  354. on_use = function(itemstack, user, pointed_thing)
  355. local seednum=0
  356. local name = user:get_player_name()
  357. local privs = minetest.get_player_privs(name)
  358. if pointed_thing.type ~= "node" then
  359. return itemstack
  360. end
  361. local charge = 65535 - itemstack:get_wear()
  362. if not charge or
  363. charge < farmingNG.seeder_charge_per_node then
  364. minetest.chat_send_player(name,S(" *** Your device needs to be serviced"))
  365. return
  366. end
  367. local inv = user:get_inventory()
  368. local indexnumber = user:get_wield_index()+1
  369. local seedstack = inv:get_stack("main", indexnumber)
  370. local seedname = seedstack:get_name()
  371. if minetest.is_protected(pointed_thing.under, name) then
  372. minetest.record_protection_violation(pointed_thing.under, name)
  373. return
  374. end
  375. if seedname then
  376. if check_valid_seed(seedname) or check_valid_util(seedname) then
  377. charge, seednum, seedstack = seeder_dig(pointed_thing.under, charge, seednum, seedstack, user)
  378. if farmingNG.chaton then
  379. minetest.chat_send_player(name,S("*** You used : @1 seeds.",seednum) .. "\n" ..
  380. S("Charge for @1 seeds left.",math.floor(charge/farmingNG.seeder_charge_per_node))
  381. )
  382. end
  383. else
  384. minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
  385. end
  386. else
  387. minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
  388. end
  389. itemstack:set_wear(65535-charge)
  390. inv:set_stack("main", indexnumber, seedstack)
  391. return itemstack
  392. end,
  393. })
  394. minetest.register_craft({
  395. output = "farming_nextgen:seeder",
  396. recipe = {
  397. {"default:mese", "default:mese_crystal_fragment", "default:mese" },
  398. {"default:gold_ingot", "default:bronze_ingot", "default:gold_ingot"},
  399. {"default:diamond", "", "default:diamond"},
  400. }
  401. })
  402. end