init.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. --[[
  2. Farming Redo Mod
  3. by TenPlus1
  4. NEW growing routine by prestidigitator
  5. auto-refill by crabman77
  6. ]]
  7. farming = {
  8. mod = "redo",
  9. version = "20211204",
  10. path = minetest.get_modpath("farming"),
  11. select = {
  12. type = "fixed",
  13. fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5}
  14. },
  15. registered_plants = {},
  16. min_light = 12,
  17. max_light = 15
  18. }
  19. local creative_mode_cache = minetest.settings:get_bool("creative_mode")
  20. function farming.is_creative(name)
  21. return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
  22. end
  23. local statistics = dofile(farming.path .. "/statistics.lua")
  24. -- Intllib
  25. local S
  26. if minetest.get_translator ~= nil then
  27. S = minetest.get_translator("farming") -- 5.x translation function
  28. else
  29. if minetest.get_modpath("intllib") then
  30. dofile(minetest.get_modpath("intllib") .. "/init.lua")
  31. if intllib.make_gettext_pair then
  32. gettext, ngettext = intllib.make_gettext_pair() -- new gettext method
  33. else
  34. gettext = intllib.Getter() -- old text file method
  35. end
  36. S = gettext
  37. else -- boilerplate function
  38. S = function(str, ...)
  39. local args = {...}
  40. return str:gsub("@%d+", function(match)
  41. return args[tonumber(match:sub(2))]
  42. end)
  43. end
  44. end
  45. end
  46. farming.intllib = S
  47. -- Utility Function
  48. local time_speed = tonumber(minetest.settings:get("time_speed")) or 72
  49. local SECS_PER_CYCLE = (time_speed > 0 and (24 * 60 * 60) / time_speed) or 0
  50. local function clamp(x, min, max)
  51. return (x < min and min) or (x > max and max) or x
  52. end
  53. -- return amount of day or night that has elapsed
  54. -- dt is time elapsed, count_day if true counts day, otherwise night
  55. local function day_or_night_time(dt, count_day)
  56. local t_day = minetest.get_timeofday()
  57. local t1_day = t_day - dt / SECS_PER_CYCLE
  58. local t1_c, t2_c -- t1_c < t2_c and t2_c always in [0, 1)
  59. if count_day then
  60. if t_day < 0.25 then
  61. t1_c = t1_day + 0.75 -- Relative to sunup, yesterday
  62. t2_c = t_day + 0.75
  63. else
  64. t1_c = t1_day - 0.25 -- Relative to sunup, today
  65. t2_c = t_day - 0.25
  66. end
  67. else
  68. if t_day < 0.75 then
  69. t1_c = t1_day + 0.25 -- Relative to sundown, yesterday
  70. t2_c = t_day + 0.25
  71. else
  72. t1_c = t1_day - 0.75 -- Relative to sundown, today
  73. t2_c = t_day - 0.75
  74. end
  75. end
  76. local dt_c = clamp(t2_c, 0, 0.5) - clamp(t1_c, 0, 0.5) -- this cycle
  77. if t1_c < -0.5 then
  78. local nc = math.floor(-t1_c)
  79. t1_c = t1_c + nc
  80. dt_c = dt_c + 0.5 * nc + clamp(-t1_c - 0.5, 0, 0.5)
  81. end
  82. return dt_c * SECS_PER_CYCLE
  83. end
  84. -- Growth Logic
  85. local STAGE_LENGTH_AVG = tonumber(
  86. minetest.settings:get("farming_stage_length")) or 200 -- 160
  87. local STAGE_LENGTH_DEV = STAGE_LENGTH_AVG / 6
  88. -- return plant name and stage from node provided
  89. local function plant_name_stage(node)
  90. local name
  91. if type(node) == "table" then
  92. if node.name then
  93. name = node.name
  94. elseif node.x and node.y and node.z then
  95. node = minetest.get_node_or_nil(node)
  96. name = node and node.name
  97. end
  98. else
  99. name = tostring(node)
  100. end
  101. if not name or name == "ignore" then
  102. return nil
  103. end
  104. local sep_pos = name:find("_[^_]+$")
  105. if sep_pos and sep_pos > 1 then
  106. local stage = tonumber(name:sub(sep_pos + 1))
  107. if stage and stage >= 0 then
  108. return name:sub(1, sep_pos - 1), stage
  109. end
  110. end
  111. return name, 0
  112. end
  113. -- Map from node name to
  114. -- { plant_name = ..., name = ..., stage = n, stages_left = { node_name, ... } }
  115. local plant_stages = {}
  116. farming.plant_stages = plant_stages
  117. --- Registers the stages of growth of a (possible plant) node.
  118. --
  119. -- @param node
  120. -- Node or position table, or node name.
  121. -- @return
  122. -- The (possibly zero) number of stages of growth the plant will go through
  123. -- before being fully grown, or nil if not a plant.
  124. local register_plant_node
  125. -- Recursive helper
  126. local function reg_plant_stages(plant_name, stage, force_last)
  127. local node_name = plant_name and plant_name .. "_" .. stage
  128. local node_def = node_name and minetest.registered_nodes[node_name]
  129. if not node_def then
  130. return nil
  131. end
  132. local stages = plant_stages[node_name]
  133. if stages then
  134. return stages
  135. end
  136. if minetest.get_item_group(node_name, "growing") > 0 then
  137. local ns = reg_plant_stages(plant_name, stage + 1, true)
  138. local stages_left = (ns and { ns.name, unpack(ns.stages_left) }) or {}
  139. stages = {
  140. plant_name = plant_name,
  141. name = node_name,
  142. stage = stage,
  143. stages_left = stages_left
  144. }
  145. if #stages_left > 0 then
  146. local old_constr = node_def.on_construct
  147. local old_destr = node_def.on_destruct
  148. minetest.override_item(node_name,
  149. {
  150. on_construct = function(pos)
  151. if old_constr then
  152. old_constr(pos)
  153. end
  154. farming.handle_growth(pos)
  155. end,
  156. on_destruct = function(pos)
  157. minetest.get_node_timer(pos):stop()
  158. if old_destr then
  159. old_destr(pos)
  160. end
  161. end,
  162. on_timer = function(pos, elapsed)
  163. return farming.plant_growth_timer(pos, elapsed, node_name)
  164. end,
  165. })
  166. end
  167. elseif force_last then
  168. stages = {
  169. plant_name = plant_name,
  170. name = node_name,
  171. stage = stage,
  172. stages_left = {}
  173. }
  174. else
  175. return nil
  176. end
  177. plant_stages[node_name] = stages
  178. return stages
  179. end
  180. local register_plant_node = function(node)
  181. local plant_name, stage = plant_name_stage(node)
  182. if plant_name then
  183. local stages = reg_plant_stages(plant_name, stage, false)
  184. return stages and #stages.stages_left
  185. else
  186. return nil
  187. end
  188. end
  189. local function set_growing(pos, stages_left)
  190. if not stages_left then
  191. return
  192. end
  193. local timer = minetest.get_node_timer(pos)
  194. if stages_left > 0 then
  195. if not timer:is_started() then
  196. local stage_length = statistics.normal(STAGE_LENGTH_AVG, STAGE_LENGTH_DEV)
  197. stage_length = clamp(stage_length, 0.5 * STAGE_LENGTH_AVG, 3.0 * STAGE_LENGTH_AVG)
  198. timer:set(stage_length, -0.5 * math.random() * STAGE_LENGTH_AVG)
  199. end
  200. elseif timer:is_started() then
  201. timer:stop()
  202. end
  203. end
  204. -- detects a crop at given position, starting or stopping growth timer when needed
  205. function farming.handle_growth(pos, node)
  206. if not pos then
  207. return
  208. end
  209. local stages_left = register_plant_node(node or pos)
  210. if stages_left then
  211. set_growing(pos, stages_left)
  212. end
  213. end
  214. minetest.after(0, function()
  215. for _, node_def in pairs(minetest.registered_nodes) do
  216. register_plant_node(node_def)
  217. end
  218. end)
  219. -- Just in case a growing type or added node is missed (also catches existing
  220. -- nodes added to map before timers were incorporated).
  221. minetest.register_abm({
  222. nodenames = {"group:growing"},
  223. interval = 300,
  224. chance = 1,
  225. catch_up = false,
  226. action = function(pos, node)
  227. farming.handle_growth(pos, node)
  228. end
  229. })
  230. -- Plant timer function that grows plants under the right conditions.
  231. function farming.plant_growth_timer(pos, elapsed, node_name)
  232. local stages = plant_stages[node_name]
  233. if not stages then
  234. return false
  235. end
  236. local max_growth = #stages.stages_left
  237. if max_growth <= 0 then
  238. return false
  239. end
  240. -- custom growth check
  241. local chk = minetest.registered_nodes[node_name].growth_check
  242. if chk then
  243. if chk(pos, node_name) then
  244. return true
  245. end
  246. -- otherwise check for wet soil beneath crop
  247. else
  248. local under = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
  249. if minetest.get_item_group(under.name, "soil") < 3 then
  250. return true
  251. end
  252. end
  253. local growth
  254. local light_pos = {x = pos.x, y = pos.y, z = pos.z}
  255. local lambda = elapsed / STAGE_LENGTH_AVG
  256. if lambda < 0.1 then
  257. return true
  258. end
  259. local MIN_LIGHT = minetest.registered_nodes[node_name].minlight or farming.min_light
  260. local MAX_LIGHT = minetest.registered_nodes[node_name].maxlight or farming.max_light
  261. if max_growth == 1 or lambda < 2.0 then
  262. local light = (minetest.get_node_light(light_pos) or 0)
  263. if light < MIN_LIGHT or light > MAX_LIGHT then
  264. return true
  265. end
  266. growth = 1
  267. else
  268. local night_light = (minetest.get_node_light(light_pos, 0) or 0)
  269. local day_light = (minetest.get_node_light(light_pos, 0.5) or 0)
  270. local night_growth = night_light >= MIN_LIGHT and night_light <= MAX_LIGHT
  271. local day_growth = day_light >= MIN_LIGHT and day_light <= MAX_LIGHT
  272. if not night_growth then
  273. if not day_growth then
  274. return true
  275. end
  276. lambda = day_or_night_time(elapsed, true) / STAGE_LENGTH_AVG
  277. elseif not day_growth then
  278. lambda = day_or_night_time(elapsed, false) / STAGE_LENGTH_AVG
  279. end
  280. growth = statistics.poisson(lambda, max_growth)
  281. if growth < 1 then
  282. return true
  283. end
  284. end
  285. if minetest.registered_nodes[stages.stages_left[growth]] then
  286. local p2 = minetest.registered_nodes[stages.stages_left[growth] ].place_param2 or 1
  287. minetest.swap_node(pos, {name = stages.stages_left[growth], param2 = p2})
  288. else
  289. return true
  290. end
  291. return growth ~= max_growth
  292. end
  293. -- refill placed plant by crabman (26/08/2015) updated by TenPlus1
  294. function farming.refill_plant(player, plantname, index)
  295. local inv = player:get_inventory()
  296. local old_stack = inv:get_stack("main", index)
  297. if old_stack:get_name() ~= "" then
  298. return
  299. end
  300. for i, stack in ipairs(inv:get_list("main")) do
  301. if stack:get_name() == plantname and i ~= index then
  302. inv:set_stack("main", index, stack)
  303. stack:clear()
  304. inv:set_stack("main", i, stack)
  305. return
  306. end
  307. end
  308. end
  309. -- Place Seeds on Soil
  310. function farming.place_seed(itemstack, placer, pointed_thing, plantname)
  311. local pt = pointed_thing
  312. -- check if pointing at a node
  313. if not pt or pt.type ~= "node" then
  314. return
  315. end
  316. local under = minetest.get_node(pt.under)
  317. -- am I right-clicking on something that has a custom on_place set?
  318. -- thanks to Krock for helping with this issue :)
  319. local def = minetest.registered_nodes[under.name]
  320. if placer and itemstack and def and def.on_rightclick then
  321. return def.on_rightclick(pt.under, under, placer, itemstack, pt)
  322. end
  323. local above = minetest.get_node(pt.above)
  324. -- check if pointing at the top of the node
  325. if pt.above.y ~= pt.under.y + 1 then
  326. return
  327. end
  328. -- return if any of the nodes is not registered
  329. if not minetest.registered_nodes[under.name]
  330. or not minetest.registered_nodes[above.name] then
  331. return
  332. end
  333. -- can I replace above node, and am I pointing at soil
  334. if not minetest.registered_nodes[above.name].buildable_to
  335. or minetest.get_item_group(under.name, "soil") < 2
  336. -- avoid multiple seed placement bug
  337. or minetest.get_item_group(above.name, "plant") ~= 0 then
  338. return
  339. end
  340. -- is player planting seed?
  341. local name = placer and placer:get_player_name() or ""
  342. -- if not protected then add node and remove 1 item from the itemstack
  343. if not minetest.is_protected(pt.above, name) then
  344. local p2 = minetest.registered_nodes[plantname].place_param2 or 1
  345. minetest.set_node(pt.above, {name = plantname, param2 = p2})
  346. --minetest.get_node_timer(pt.above):start(1)
  347. --farming.handle_growth(pt.above)--, node)
  348. minetest.sound_play("default_place_node", {pos = pt.above, gain = 1.0})
  349. if placer and itemstack
  350. and not farming.is_creative(placer:get_player_name()) then
  351. local name = itemstack:get_name()
  352. itemstack:take_item()
  353. -- check for refill
  354. if itemstack:get_count() == 0 then
  355. minetest.after(0.10,
  356. farming.refill_plant,
  357. placer,
  358. name,
  359. placer:get_wield_index()
  360. )
  361. end
  362. end
  363. return itemstack
  364. end
  365. end
  366. -- Function to register plants (default farming compatibility)
  367. farming.register_plant = function(name, def)
  368. if not def.steps then
  369. return nil
  370. end
  371. local mname = name:split(":")[1]
  372. local pname = name:split(":")[2]
  373. -- Check def
  374. def.description = def.description or S("Seed")
  375. def.inventory_image = def.inventory_image or "unknown_item.png"
  376. def.minlight = def.minlight or 12
  377. def.maxlight = def.maxlight or 15
  378. -- Register seed
  379. minetest.register_node(":" .. mname .. ":seed_" .. pname, {
  380. description = def.description,
  381. tiles = {def.inventory_image},
  382. inventory_image = def.inventory_image,
  383. wield_image = def.inventory_image,
  384. drawtype = "signlike",
  385. groups = {seed = 1, snappy = 3, attached_node = 1, flammable = 2},
  386. paramtype = "light",
  387. paramtype2 = "wallmounted",
  388. walkable = false,
  389. sunlight_propagates = true,
  390. selection_box = farming.select,
  391. place_param2 = def.place_param2 or nil,
  392. next_plant = mname .. ":" .. pname .. "_1",
  393. on_place = function(itemstack, placer, pointed_thing)
  394. return farming.place_seed(itemstack, placer,
  395. pointed_thing, mname .. ":" .. pname .. "_1")
  396. end,
  397. })
  398. -- Register harvest
  399. minetest.register_craftitem(":" .. mname .. ":" .. pname, {
  400. description = pname:gsub("^%l", string.upper),
  401. inventory_image = mname .. "_" .. pname .. ".png",
  402. groups = def.groups or {flammable = 2},
  403. })
  404. -- Register growing steps
  405. for i = 1, def.steps do
  406. local base_rarity = 1
  407. if def.steps ~= 1 then
  408. base_rarity = 8 - (i - 1) * 7 / (def.steps - 1)
  409. end
  410. local drop = {
  411. items = {
  412. {items = {mname .. ":" .. pname}, rarity = base_rarity},
  413. {items = {mname .. ":" .. pname}, rarity = base_rarity * 2},
  414. {items = {mname .. ":seed_" .. pname}, rarity = base_rarity},
  415. {items = {mname .. ":seed_" .. pname}, rarity = base_rarity * 2},
  416. }
  417. }
  418. local g = {
  419. snappy = 3, flammable = 2, plant = 1, growing = 1,
  420. attached_node = 1, not_in_creative_inventory = 1,
  421. }
  422. -- Last step doesn't need growing=1 so Abm never has to check these
  423. if i == def.steps then
  424. g.growing = 0
  425. end
  426. local node_name = mname .. ":" .. pname .. "_" .. i
  427. local next_plant = nil
  428. if i < def.steps then
  429. next_plant = mname .. ":" .. pname .. "_" .. (i + 1)
  430. end
  431. minetest.register_node(node_name, {
  432. drawtype = "plantlike",
  433. waving = 1,
  434. tiles = {mname .. "_" .. pname .. "_" .. i .. ".png"},
  435. paramtype = "light",
  436. paramtype2 = def.paramtype2,
  437. place_param2 = def.place_param2,
  438. walkable = false,
  439. buildable_to = true,
  440. sunlight_propagates = true,
  441. drop = drop,
  442. selection_box = farming.select,
  443. groups = g,
  444. sounds = default.node_sound_leaves_defaults(),
  445. minlight = def.minlight,
  446. maxlight = def.maxlight,
  447. next_plant = next_plant
  448. })
  449. end
  450. -- add to farming.registered_plants
  451. farming.registered_plants[mname .. ":" .. pname] = {
  452. crop = mname .. ":" .. pname,
  453. seed = mname .. ":seed_" .. pname,
  454. steps = def.steps,
  455. minlight = def.minlight,
  456. maxlight = def.maxlight
  457. }
  458. --print(dump(farming.registered_plants[mname .. ":" .. pname]))
  459. -- Return info
  460. return {seed = mname .. ":seed_" .. pname, harvest = mname .. ":" .. pname}
  461. end
  462. -- default settings
  463. farming.carrot = 0.001
  464. farming.potato = 0.001
  465. farming.tomato = 0.001
  466. farming.cucumber = 0.001
  467. farming.corn = 0.001
  468. farming.coffee = 0.001
  469. farming.melon = 0.001
  470. farming.pumpkin = 0.001
  471. farming.cocoa = true
  472. farming.raspberry = 0.001
  473. farming.blueberry = 0.001
  474. farming.rhubarb = 0.001
  475. farming.beans = 0.001
  476. farming.grapes = 0.001
  477. farming.barley = true
  478. farming.chili = 0.003
  479. farming.hemp = 0.003
  480. farming.garlic = 0.001
  481. farming.onion = 0.001
  482. farming.pepper = 0.002
  483. farming.pineapple = 0.001
  484. farming.peas = 0.001
  485. farming.beetroot = 0.001
  486. farming.mint = 0.005
  487. farming.cabbage = 0.001
  488. farming.blackberry = 0.002
  489. farming.soy = 0.001
  490. farming.vanilla = 0.001
  491. farming.lettuce = 0.001
  492. farming.artichoke = 0.001
  493. farming.parsley = 0.002
  494. farming.sunflower = 0.001
  495. farming.grains = true
  496. farming.rice = true
  497. farming.rarety = 0.002
  498. -- Load new global settings if found inside mod folder
  499. local input = io.open(farming.path.."/farming.conf", "r")
  500. if input then
  501. dofile(farming.path .. "/farming.conf")
  502. input:close()
  503. end
  504. -- load new world-specific settings if found inside world folder
  505. local worldpath = minetest.get_worldpath()
  506. input = io.open(worldpath.."/farming.conf", "r")
  507. if input then
  508. dofile(worldpath .. "/farming.conf")
  509. input:close()
  510. end
  511. -- important items
  512. dofile(farming.path.."/soil.lua")
  513. dofile(farming.path.."/hoes.lua")
  514. dofile(farming.path.."/grass.lua")
  515. dofile(farming.path.."/utensils.lua")
  516. -- default crops
  517. dofile(farming.path.."/crops/wheat.lua")
  518. dofile(farming.path.."/crops/cotton.lua")
  519. -- helper function
  520. local function ddoo(file, check)
  521. if check then
  522. dofile(farming.path .. "/crops/" .. file)
  523. end
  524. end
  525. -- add additional crops and food (if enabled)
  526. ddoo("carrot.lua", farming.carrot)
  527. ddoo("potato.lua", farming.potato)
  528. ddoo("tomato.lua", farming.tomato)
  529. ddoo("cucumber.lua", farming.cucumber)
  530. ddoo("corn.lua", farming.corn)
  531. ddoo("coffee.lua", farming.coffee)
  532. ddoo("melon.lua", farming.melon)
  533. ddoo("pumpkin.lua", farming.pumpkin)
  534. ddoo("cocoa.lua", farming.cocoa)
  535. ddoo("raspberry.lua", farming.raspberry)
  536. ddoo("blueberry.lua", farming.blueberry)
  537. ddoo("rhubarb.lua", farming.rhubarb)
  538. ddoo("beans.lua", farming.beans)
  539. ddoo("grapes.lua", farming.grapes)
  540. ddoo("barley.lua", farming.barley)
  541. ddoo("hemp.lua", farming.hemp)
  542. ddoo("garlic.lua", farming.garlic)
  543. ddoo("onion.lua", farming.onion)
  544. ddoo("pepper.lua", farming.pepper)
  545. ddoo("pineapple.lua", farming.pineapple)
  546. ddoo("peas.lua", farming.peas)
  547. ddoo("beetroot.lua", farming.beetroot)
  548. ddoo("chili.lua", farming.chili)
  549. ddoo("ryeoatrice.lua", farming.grains)
  550. ddoo("rice.lua", farming.rice)
  551. ddoo("mint.lua", farming.mint)
  552. ddoo("cabbage.lua", farming.cabbage)
  553. ddoo("blackberry.lua", farming.blackberry)
  554. ddoo("soy.lua", farming.soy)
  555. ddoo("vanilla.lua", farming.vanilla)
  556. ddoo("lettuce.lua", farming.lettuce)
  557. ddoo("artichoke.lua", farming.artichoke)
  558. ddoo("parsley.lua", farming.parsley)
  559. ddoo("sunflower.lua", farming.sunflower)
  560. dofile(farming.path .. "/food.lua")
  561. dofile(farming.path .. "/mapgen.lua")
  562. dofile(farming.path .. "/compatibility.lua") -- Farming Plus compatibility
  563. dofile(farming.path .. "/lucky_block.lua")