init.lua 17 KB

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