init.lua 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333
  1. -- Mod: BEES
  2. -- Author: Bas080 (Tweaked by TenPlus1)
  3. -- License: MIT
  4. -- Translation support
  5. local S = minetest.get_translator("bees")
  6. --
  7. -- FUNCTIONS
  8. --
  9. local floor = math.floor
  10. local random = math.random
  11. local hive_wild = function(pos, grafting)
  12. local spos = pos.x .. "," .. pos.y .. "," ..pos.z
  13. local formspec = "size[8,9]"
  14. .. "list[nodemeta:" .. spos .. ";combs;1.5,3;5,1;]"
  15. .. "list[current_player;main;0,5;8,4;]"
  16. if grafting then
  17. formspec = formspec .."list[nodemeta:".. spos .. ";queen;3.5,1;1,1;]"
  18. end
  19. return formspec
  20. end
  21. local hive_artificial = function(pos)
  22. local spos = pos.x .. "," .. pos.y .. "," .. pos.z
  23. local formspec = "size[8,9]"
  24. .. "list[nodemeta:" .. spos .. ";queen;3.5,1;1,1;]"
  25. .. "tooltip[3.5,1;1,1;Queen]"
  26. .. "list[nodemeta:" .. spos .. ";frames;0,3;8,1;]"
  27. .. "tooltip[0,3;8,1;Frames]"
  28. .. "list[current_player;main;0,5;8,4;]"
  29. return formspec
  30. end
  31. local polinate_flower = function(pos, flower)
  32. local spawn_pos = {
  33. x = pos.x + random(-3, 3),
  34. y = pos.y + random(-3, 3),
  35. z = pos.z + random(-3, 3)
  36. }
  37. local floor_pos = {x = spawn_pos.x, y = spawn_pos.y - 1, z = spawn_pos.z}
  38. local spawn = minetest.get_node(spawn_pos).name
  39. local floorn = minetest.get_node(floor_pos).name
  40. if floorn == "group:soil" and spawn == "air" then
  41. minetest.set_node(spawn_pos, {name = flower})
  42. end
  43. end
  44. local sting_player = function(player, damage)
  45. minetest.after(0.1, function()
  46. if player and player:get_pos() then
  47. player:set_hp(player:get_hp() - damage)
  48. end
  49. end)
  50. end
  51. --
  52. -- NODES
  53. --
  54. minetest.register_node("bees:extractor", {
  55. description = S("Honey Extractor"),
  56. tiles = {
  57. "bees_extractor.png", "bees_extractor.png", "bees_extractor.png",
  58. "bees_extractor.png", "bees_extractor.png", "bees_extractor_front.png"
  59. },
  60. paramtype2 = "facedir",
  61. groups = {
  62. choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1,
  63. tubedevice_receiver = 1
  64. },
  65. on_construct = function(pos)
  66. local meta = minetest.get_meta(pos)
  67. local inv = meta:get_inventory()
  68. pos = pos.x .. "," .. pos.y .. "," .. pos.z
  69. inv:set_size("frames_filled", 1)
  70. inv:set_size("frames_emptied", 1)
  71. inv:set_size("bottles_empty", 1)
  72. inv:set_size("bottles_full", 1)
  73. inv:set_size("wax", 1)
  74. meta:set_string("formspec", "size[8,9]"
  75. -- input
  76. .. "list[nodemeta:" .. pos .. ";frames_filled;2,1;1,1;]"
  77. .. "tooltip[2,1;1,1;Filled Frames]"
  78. .. "list[nodemeta:" .. pos .. ";bottles_empty;2,3;1,1;]"
  79. .. "tooltip[2,3;1,1;Empty Bottles]"
  80. -- output
  81. .. "list[nodemeta:" .. pos .. ";frames_emptied;5,0.5;1,1;]"
  82. .. "tooltip[5,0.5;1,1;Empty Frames]"
  83. .. "list[nodemeta:" .. pos .. ";wax;5,2;1,1;]"
  84. .. "tooltip[5,2;1,1;Wax]"
  85. .. "list[nodemeta:" .. pos .. ";bottles_full;5,3.5;1,1;]"
  86. .. "tooltip[5,3.5;1,1;Filled Bottles]"
  87. -- player inventory
  88. .. "list[current_player;main;0,5;8,4;]"
  89. )
  90. end,
  91. can_dig = function(pos)
  92. local meta = minetest.get_meta(pos)
  93. local inv = meta:get_inventory()
  94. if inv:is_empty("frames_filled") and inv:is_empty("frames_emptied")
  95. and inv:is_empty("bottles_empty") and inv:is_empty("bottles_full")
  96. and inv:is_empty("wax") then
  97. return true
  98. else
  99. return false
  100. end
  101. end,
  102. on_timer = function(pos)
  103. local meta = minetest.get_meta(pos)
  104. local inv = meta:get_inventory()
  105. local timer = minetest.get_node_timer(pos)
  106. if not inv:contains_item("frames_filled", "bees:frame_full")
  107. or not inv:contains_item("bottles_empty", "vessels:glass_bottle") then
  108. return
  109. end
  110. if inv:room_for_item("frames_emptied", "bees:frame_empty")
  111. and inv:room_for_item("wax", "bees:wax")
  112. and inv:room_for_item("bottles_full", "bees:bottle_honey") then
  113. -- add to output
  114. inv:add_item("frames_emptied", "bees:frame_empty")
  115. inv:add_item("wax", "bees:wax")
  116. inv:add_item("bottles_full", "bees:bottle_honey")
  117. -- remove from input
  118. inv:remove_item("bottles_empty", "vessels:glass_bottle")
  119. inv:remove_item("frames_filled", "bees:frame_full")
  120. -- wax flying all over the place
  121. minetest.add_particle({
  122. pos = {x = pos.x, y = pos.y, z = pos.z},
  123. velocity = {
  124. x = random(-1, 1),
  125. y = random(4),
  126. z = random(-1, 1)
  127. },
  128. acceleration = {x = 0, y = -6, z = 0},
  129. expirationtime = 2,
  130. size = random(1, 3),
  131. collisiondetection = false,
  132. texture = "bees_wax_particle.png",
  133. })
  134. timer:start(5)
  135. else
  136. timer:start(5) -- try again in 5 seconds (was 1)
  137. end
  138. end,
  139. tube = {
  140. insert_object = function(pos, _, stack)
  141. local meta = minetest.get_meta(pos)
  142. local inv = meta:get_inventory()
  143. local timer = minetest.get_node_timer(pos)
  144. if stack:get_name() == "bees:frame_full" then
  145. if inv:is_empty("frames_filled") then
  146. timer:start(5)
  147. end
  148. return inv:add_item("frames_filled",stack)
  149. elseif stack:get_name() == "vessels:glass_bottle" then
  150. if inv:is_empty("bottles_empty") then
  151. timer:start(5)
  152. end
  153. return inv:add_item("bottles_empty",stack)
  154. end
  155. return stack
  156. end,
  157. can_insert = function(pos, _, stack)
  158. local meta = minetest.get_meta(pos)
  159. local inv = meta:get_inventory()
  160. if stack:get_name() == "bees:frame_full" then
  161. return inv:room_for_item("frames_filled", stack)
  162. elseif stack:get_name() == "vessels:glass_bottle" then
  163. return inv:room_for_item("bottles_empty", stack)
  164. end
  165. return false
  166. end,
  167. input_inventory = {"frames_emptied", "bottles_full", "wax"},
  168. connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
  169. },
  170. on_metadata_inventory_put = function(pos, listname, _, stack)
  171. local timer = minetest.get_node_timer(pos)
  172. local meta = minetest.get_meta(pos)
  173. local inv = meta:get_inventory()
  174. -- if inventory empty start timer for honey bottle, empty frame and wax
  175. if inv:get_stack(listname, 1):get_count() == stack:get_count() then
  176. timer:start(5)
  177. end
  178. end,
  179. allow_metadata_inventory_put = function(_, listname, _, stack)
  180. if (listname == "bottles_empty" and stack:get_name() == "vessels:glass_bottle")
  181. or (listname == "frames_filled" and stack:get_name() == "bees:frame_full") then
  182. return stack:get_count()
  183. else
  184. return 0
  185. end
  186. end,
  187. allow_metadata_inventory_move = function()
  188. return 0
  189. end,
  190. allow_metadata_inventory_take = function(pos, _, _, stack, player)
  191. if player and minetest.is_protected(pos, player:get_player_name()) then
  192. return 0
  193. end
  194. return stack:get_count()
  195. end
  196. })
  197. minetest.register_node("bees:bees", {
  198. description = S("Bees"),
  199. drawtype = "plantlike",
  200. paramtype = "light",
  201. groups = {not_in_creative_inventory = 1},
  202. tiles = {{
  203. name = "bees_strip.png",
  204. animation = {
  205. type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 2.0
  206. }
  207. }},
  208. damage_per_second = 1,
  209. walkable = false,
  210. buildable_to = true,
  211. selection_box = {
  212. type = "fixed",
  213. fixed = {
  214. {-0.3, -0.4, -0.3, 0.3, 0.4, 0.3}
  215. }
  216. },
  217. on_timer = function(pos)
  218. minetest.remove_node(pos)
  219. end,
  220. on_construct = function(pos)
  221. local timer = minetest.get_node_timer(pos)
  222. timer:start(25)
  223. minetest.sound_play("bees", {
  224. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  225. end,
  226. on_punch = function(_, _, puncher)
  227. sting_player(puncher, 2)
  228. end
  229. })
  230. minetest.register_node("bees:hive_wild", {
  231. description = S("Wild Bee Hive"),
  232. tiles = { -- Neuromancer's base texture
  233. "bees_hive_wild.png", "bees_hive_wild.png", "bees_hive_wild.png",
  234. "bees_hive_wild.png", "bees_hive_wild_bottom.png"
  235. },
  236. drawtype = "nodebox",
  237. paramtype = "light",
  238. paramtype2 = "wallmounted",
  239. drop = {
  240. max_items = 6,
  241. items = {
  242. {items = {"bees:honey_comb"}, rarity = 5}
  243. }
  244. },
  245. groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
  246. node_box = { -- VanessaE's wild hive nodebox contribution
  247. type = "fixed",
  248. fixed = {
  249. {-0.25, -0.5, -0.25, 0.25, 0.375, 0.25},
  250. {-0.3125, -0.375, -0.3125, 0.3125, 0.25, 0.3125},
  251. {-0.375, -0.25, -0.375, 0.375, 0.125, 0.375},
  252. {-0.0625, -0.5, -0.0625, 0.0625, 0.5, 0.0625}
  253. }
  254. },
  255. on_timer = function(pos)
  256. local meta = minetest.get_meta(pos)
  257. local inv = meta:get_inventory()
  258. local timer = minetest.get_node_timer(pos)
  259. local rad = 10
  260. local flowers = minetest.find_nodes_in_area(
  261. {x = pos.x - rad, y = pos.y - rad, z = pos.z - rad},
  262. {x = pos.x + rad, y = pos.y + rad, z = pos.z + rad},
  263. "group:flower")
  264. -- Queen dies if no flowers nearby
  265. if #flowers == 0 then
  266. inv:set_stack("queen", 1, "")
  267. meta:set_string("infotext", S("Colony died, not enough flowers in area!"))
  268. return
  269. end
  270. -- Requires 2 or more flowers to make honey
  271. if #flowers < 3 then return end
  272. local flower = flowers[random(#flowers)]
  273. polinate_flower(flower, minetest.get_node(flower).name)
  274. local stacks = inv:get_list("combs")
  275. for k, _ in pairs(stacks) do
  276. if inv:get_stack("combs", k):is_empty() then
  277. inv:set_stack("combs", k, "bees:honey_comb")
  278. timer:start(1000 / #flowers)
  279. return
  280. end
  281. end
  282. -- what to do if all combs are filled
  283. end,
  284. on_construct = function(pos)
  285. minetest.get_node(pos).param2 = 0
  286. local meta = minetest.get_meta(pos)
  287. local inv = meta:get_inventory()
  288. local timer = minetest.get_node_timer(pos)
  289. meta:set_int("agressive", 1)
  290. timer:start(100 + random(100))
  291. inv:set_size("queen", 1)
  292. inv:set_size("combs", 5)
  293. inv:set_stack("queen", 1, "bees:queen")
  294. for i = 1, random(3) do
  295. inv:set_stack("combs", i, "bees:honey_comb")
  296. end
  297. end,
  298. on_punch = function(pos, _, puncher)
  299. local meta = minetest.get_meta(pos)
  300. local inv = meta:get_inventory()
  301. if inv:contains_item("queen", "bees:queen") then
  302. sting_player(puncher, 4)
  303. end
  304. minetest.sound_play("bees", {
  305. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  306. end,
  307. on_metadata_inventory_take = function(pos, listname, _, _, taker)
  308. local meta = minetest.get_meta(pos)
  309. local inv = meta:get_inventory()
  310. local timer= minetest.get_node_timer(pos)
  311. if listname == "combs" and inv:contains_item("queen", "bees:queen") then
  312. timer:start(10)
  313. sting_player(taker, 2)
  314. end
  315. end,
  316. on_metadata_inventory_put = function(pos)
  317. local timer = minetest.get_node_timer(pos)
  318. if not timer:is_started() then
  319. timer:start(10)
  320. end
  321. end,
  322. allow_metadata_inventory_put = function(_, listname, _, stack)
  323. -- restart the colony by adding a queen
  324. if listname == "queen" and stack:get_name() == "bees:queen" then
  325. return 1
  326. else
  327. return 0
  328. end
  329. end,
  330. on_rightclick = function(pos, _, clicker, itemstack)
  331. if not itemstack then return end
  332. minetest.show_formspec(clicker:get_player_name(),
  333. "bees:hive_artificial",
  334. hive_wild(pos, (itemstack:get_name() == "bees:grafting_tool"))
  335. )
  336. local meta = minetest.get_meta(pos)
  337. local inv = meta:get_inventory()
  338. if meta:get_int("agressive") == 1
  339. and inv:contains_item("queen", "bees:queen") then
  340. minetest.sound_play("bees", {
  341. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  342. sting_player(clicker, 4)
  343. else
  344. meta:set_int("agressive", 1)
  345. end
  346. end,
  347. can_dig = function(pos)
  348. local meta = minetest.get_meta(pos)
  349. local inv = meta:get_inventory()
  350. if inv:is_empty("queen") and inv:is_empty("combs") then
  351. return true
  352. else
  353. return false
  354. end
  355. end,
  356. after_dig_node = function(_, _, _, user)
  357. local wielded
  358. if user:get_wielded_item() ~= nil then
  359. wielded = user:get_wielded_item()
  360. else
  361. return
  362. end
  363. if "bees:grafting_tool" == wielded:get_name() then
  364. local inv = user:get_inventory()
  365. if inv then
  366. inv:add_item("main", ItemStack("bees:queen"))
  367. end
  368. end
  369. end
  370. })
  371. minetest.register_node("bees:hive_artificial", {
  372. description = S("Artificial Bee Hive"),
  373. tiles = {
  374. "default_wood.png", "default_wood.png", "default_wood.png",
  375. "default_wood.png", "default_wood.png", "bees_hive_artificial.png"
  376. },
  377. drawtype = "nodebox",
  378. paramtype = "light",
  379. paramtype2 = "facedir",
  380. groups = {
  381. snappy = 1, choppy = 2, oddly_breakable_by_hand = 2,
  382. flammable = 3, wood = 1
  383. },
  384. sounds = default.node_sound_wood_defaults(),
  385. node_box = {
  386. type = "fixed",
  387. fixed = {
  388. {-4/8, 2/8, -4/8, 4/8, 3/8, 4/8},
  389. {-3/8, -4/8, -2/8, 3/8, 2/8, 3/8},
  390. {-3/8, 0/8, -3/8, 3/8, 2/8, -2/8},
  391. {-3/8, -4/8, -3/8, 3/8, -1/8, -2/8},
  392. {-3/8, -1/8, -3/8, -1/8, 0/8, -2/8},
  393. {1/8, -1/8, -3/8, 3/8, 0/8, -2/8},
  394. }
  395. },
  396. on_construct = function(pos)
  397. local meta = minetest.get_meta(pos)
  398. local inv = meta:get_inventory()
  399. meta:set_int("agressive", 1)
  400. inv:set_size("queen", 1)
  401. inv:set_size("frames", 8)
  402. meta:set_string("infotext", S("Requires Queen bee to function"))
  403. end,
  404. on_rightclick = function(pos, _, clicker)
  405. local player_name = clicker:get_player_name()
  406. if minetest.is_protected(pos, player_name) then
  407. return
  408. end
  409. minetest.show_formspec(player_name,
  410. "bees:hive_artificial",
  411. hive_artificial(pos)
  412. )
  413. local meta = minetest.get_meta(pos)
  414. local inv = meta:get_inventory()
  415. if meta:get_int("agressive") == 1
  416. and inv:contains_item("queen", "bees:queen") then
  417. sting_player(clicker, 4)
  418. else
  419. meta:set_int("agressive", 1)
  420. end
  421. end,
  422. on_timer = function(pos)
  423. local meta = minetest.get_meta(pos)
  424. local inv = meta:get_inventory()
  425. local timer = minetest.get_node_timer(pos)
  426. if inv:contains_item("queen", "bees:queen") then
  427. if inv:contains_item("frames", "bees:frame_empty") then
  428. timer:start(30)
  429. local rad = 10
  430. local flowers = minetest.find_nodes_in_area(
  431. {x = pos.x - rad, y = pos.y - rad, z = pos.z - rad},
  432. {x = pos.x + rad, y = pos.y + rad, z = pos.z + rad},
  433. "group:flower")
  434. local progress = meta:get_int("progress")
  435. progress = progress + #flowers
  436. meta:set_int("progress", progress)
  437. if progress > 1000 then
  438. local flower = flowers[random(#flowers)]
  439. polinate_flower(flower, minetest.get_node(flower).name)
  440. local stacks = inv:get_list("frames")
  441. for k, _ in pairs(stacks) do
  442. if inv:get_stack("frames", k):get_name() == "bees:frame_empty" then
  443. meta:set_int("progress", 0)
  444. inv:set_stack("frames", k, "bees:frame_full")
  445. return
  446. end
  447. end
  448. else
  449. meta:set_string("infotext", S("progress:")
  450. .. " " .. progress .. " + " .. #flowers .. " / 1000")
  451. end
  452. else
  453. meta:set_string("infotext", S("Does not have empty frame(s)"))
  454. timer:stop()
  455. end
  456. end
  457. end,
  458. on_metadata_inventory_take = function(pos, listname)
  459. if listname == "queen" then
  460. local timer = minetest.get_node_timer(pos)
  461. local meta = minetest.get_meta(pos)
  462. meta:set_string("infotext", S("Requires Queen bee to function"))
  463. timer:stop()
  464. end
  465. end,
  466. allow_metadata_inventory_move = function(pos, from_list, _, to_list, to_index)
  467. local inv = minetest.get_meta(pos):get_inventory()
  468. if from_list == to_list then
  469. if inv:get_stack(to_list, to_index):is_empty() then
  470. return 1
  471. else
  472. return 0
  473. end
  474. else
  475. return 0
  476. end
  477. end,
  478. on_metadata_inventory_put = function(pos, listname, _, stack)
  479. local meta = minetest.get_meta(pos)
  480. local inv = meta:get_inventory()
  481. local timer = minetest.get_node_timer(pos)
  482. if listname == "queen" or listname == "frames" then
  483. meta:set_string("queen", stack:get_name())
  484. meta:set_string("infotext", S("Queen inserted, now for the empty frames"))
  485. if inv:contains_item("frames", "bees:frame_empty") then
  486. timer:start(30)
  487. meta:set_string("infotext", S("Bees are aclimating"))
  488. end
  489. end
  490. end,
  491. allow_metadata_inventory_put = function(pos, listname, index, stack)
  492. if not minetest.get_meta(pos):get_inventory():get_stack(listname, index):is_empty() then return 0 end
  493. if listname == "queen" then
  494. if stack:get_name():match("bees:queen*") then
  495. return 1
  496. end
  497. elseif listname == "frames" then
  498. if stack:get_name() == ("bees:frame_empty") then
  499. return 1
  500. end
  501. end
  502. return 0
  503. end,
  504. can_dig = function(pos)
  505. local meta = minetest.get_meta(pos)
  506. local inv = meta:get_inventory()
  507. if inv:is_empty("queen") and inv:is_empty("frames") then
  508. return true
  509. else
  510. return false
  511. end
  512. end
  513. })
  514. --
  515. -- ABMs
  516. --
  517. minetest.register_abm({
  518. label = "spawn bee particles",
  519. nodenames = {"bees:hive_artificial", "bees:hive_wild", "bees:hive_industrial"},
  520. interval = 10,
  521. chance = 4,
  522. action = function(pos, node)
  523. -- Bee particle
  524. minetest.add_particle({
  525. pos = {x = pos.x, y = pos.y, z = pos.z},
  526. velocity = {
  527. x = (random() - 0.5) * 5,
  528. y = (random() - 0.5) * 5,
  529. z = (random() - 0.5) * 5
  530. },
  531. acceleration = {
  532. x = random() - 0.5,
  533. y = random() - 0.5,
  534. z = random() - 0.5
  535. },
  536. expirationtime = random(2.5),
  537. size = random(3),
  538. collisiondetection = true,
  539. texture = "bees_particle_bee.png",
  540. })
  541. minetest.sound_play("bees", {
  542. pos = pos, gain = 0.6, max_hear_distance = 5}, true)
  543. -- floating hive check and removal
  544. if node.name == "bees:hive_wild" then
  545. local num = #minetest.find_nodes_in_area(
  546. {x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
  547. {x = pos.x + 1, y = pos.y + 1, z = pos.z + 1},
  548. {"air"})
  549. if num and num > 25 then
  550. minetest.remove_node(pos)
  551. end
  552. end
  553. end
  554. })
  555. -- spawn ABM. This should be changed to a more realistic type of spawning
  556. minetest.register_abm({
  557. label = "spawn bee hives",
  558. nodenames = {"group:leaves"},
  559. neighbors = {"air"},
  560. interval = 300,
  561. chance = 4,
  562. action = function(pos)
  563. if floor(pos.x / 20) ~= pos.x / 20
  564. or floor(pos.z / 20) ~= pos.z / 20
  565. or floor(pos.y / 3) ~= pos.y / 3 then return end
  566. local p = {x = pos.x, y = pos.y - 1, z = pos.z}
  567. -- skip if nearby hive found
  568. if minetest.find_node_near(p, 25, {"bees:hive_artificial", "bees:hive_wild",
  569. "bees:hive_industrial"}) then
  570. return
  571. end
  572. local nod = minetest.get_node_or_nil(p)
  573. local def = nod and minetest.registered_nodes[nod.name]
  574. if not def or def.walkable then return end
  575. if minetest.find_node_near(p, 5, "group:flora") then
  576. minetest.add_node(p, {name = "bees:hive_wild"})
  577. end
  578. end
  579. })
  580. -- spawning bees around bee hive
  581. minetest.register_abm({
  582. label = "spawn bees around bee hives",
  583. nodenames = {"bees:hive_wild", "bees:hive_artificial", "bees:hive_industrial"},
  584. neighbors = {"group:flower", "group:leaves"},
  585. interval = 30,
  586. chance = 4,
  587. action = function(pos)
  588. local p = {
  589. x = pos.x + random(-5, 5),
  590. y = pos.y - random(0, 3),
  591. z = pos.z + random(-5, 5)
  592. }
  593. if minetest.get_node(p).name == "air" then
  594. minetest.add_node(p, {name="bees:bees"})
  595. end
  596. end
  597. })
  598. --
  599. -- ITEMS
  600. --
  601. minetest.register_craftitem("bees:frame_empty", {
  602. description = S("Empty Hive Frame"),
  603. inventory_image = "bees_frame_empty.png",
  604. stack_max = 24
  605. })
  606. minetest.register_craftitem("bees:frame_full", {
  607. description = S("Filled Hive Frame"),
  608. inventory_image = "bees_frame_full.png",
  609. stack_max = 12
  610. })
  611. minetest.register_craftitem("bees:bottle_honey", {
  612. description = S("Honey Bottle"),
  613. inventory_image = "bees_bottle_honey.png",
  614. stack_max = 12,
  615. on_use = minetest.item_eat(3, "vessels:glass_bottle"),
  616. groups = {vessel = 1}
  617. })
  618. minetest.register_craftitem("bees:wax", {
  619. description = S("Bees Wax"),
  620. inventory_image = "bees_wax.png",
  621. stack_max = 48
  622. })
  623. minetest.register_craftitem("bees:honey_comb", {
  624. description = S("Honey Comb"),
  625. inventory_image = "bees_comb.png",
  626. on_use = minetest.item_eat(2),
  627. stack_max = 8
  628. })
  629. minetest.register_craftitem("bees:queen", {
  630. description = S("Queen Bee"),
  631. inventory_image = "bees_particle_bee.png",
  632. stack_max = 1
  633. })
  634. --
  635. -- CRAFTS
  636. --
  637. minetest.register_craft({
  638. output = "bees:extractor",
  639. recipe = {
  640. {"", "default:steel_ingot", ""},
  641. {"default:steel_ingot", "default:stick", "default:steel_ingot"},
  642. {"default:mese_crystal", "default:steel_ingot", "default:mese_crystal"}
  643. }
  644. })
  645. minetest.register_craft({
  646. output = "bees:smoker",
  647. recipe = {
  648. {"default:steel_ingot", "wool:red", ""},
  649. {"", "default:torch", ""},
  650. {"", "default:steel_ingot",""}
  651. }
  652. })
  653. minetest.register_craft({
  654. output = "bees:hive_artificial",
  655. recipe = {
  656. {"group:wood", "group:wood", "group:wood"},
  657. {"group:wood", "default:stick", "group:wood"},
  658. {"group:wood", "default:stick", "group:wood"}
  659. }
  660. })
  661. minetest.register_craft({
  662. output = "bees:grafting_tool",
  663. recipe = {
  664. {"", "", "default:steel_ingot"},
  665. {"", "default:stick", ""},
  666. {"", "", ""}
  667. }
  668. })
  669. minetest.register_craft({
  670. output = "bees:frame_empty",
  671. recipe = {
  672. {"group:wood", "group:wood", "group:wood"},
  673. {"default:stick", "default:stick", "default:stick"},
  674. {"default:stick", "default:stick", "default:stick"}
  675. }
  676. })
  677. if minetest.get_modpath("bushes_classic") then
  678. minetest.register_craft({
  679. type = "cooking",
  680. cooktime = 5,
  681. recipe = "bees:bottle_honey",
  682. output = "bushes:sugar"
  683. })
  684. end
  685. --
  686. -- TOOLS
  687. --
  688. minetest.register_tool("bees:smoker", {
  689. description = S("Smoker"),
  690. inventory_image = "bees_smoker.png",
  691. tool_capabilities = {
  692. full_punch_interval = 3.0,
  693. max_drop_level = 0,
  694. damage_groups = {fleshy = 2}
  695. },
  696. on_use = function(itemstack, _, pointed_thing)
  697. if pointed_thing.type ~= "node" then
  698. return
  699. end
  700. local pos = pointed_thing.under
  701. for i = 1, 6 do
  702. minetest.add_particle({
  703. pos = {
  704. x = pos.x + random() - 0.5,
  705. y = pos.y,
  706. z = pos.z + random() - 0.5
  707. },
  708. velocity = {x = 0, y = 0.5 + random(), z = 0},
  709. acceleration = {x = 0, y = 0, z = 0},
  710. expirationtime = 2 + random(2.5),
  711. size = random(3),
  712. collisiondetection = false,
  713. texture = "bees_smoke_particle.png"
  714. })
  715. end
  716. itemstack:add_wear(65535 / 200)
  717. local nodename = minetest.get_node(pos).name or ""
  718. if nodename:find("bees:hive_") then
  719. local meta = minetest.get_meta(pos)
  720. meta:set_int("agressive", 0)
  721. end
  722. return itemstack
  723. end
  724. })
  725. minetest.register_tool("bees:grafting_tool", {
  726. description = S("Grafting Tool"),
  727. inventory_image = "bees_grafting_tool.png",
  728. tool_capabilities = {
  729. full_punch_interval = 3.0,
  730. max_drop_level = 0,
  731. damage_groups = {fleshy = 2}
  732. }
  733. })
  734. --
  735. -- COMPATIBILTY
  736. -- remove after all has been updated
  737. --
  738. -- ALIASES
  739. minetest.register_alias("bees:honey_extractor", "bees:extractor")
  740. -- BACKWARDS COMPATIBILITY WITH OLDER VERSION
  741. minetest.register_alias("bees:honey_bottle", "bees:bottle_honey")
  742. minetest.register_lbm({
  743. nodenames = {"bees:hive", "bees:hive_artificial_inhabited", "bees:bees"},
  744. name = "bees:replace_old_hives",
  745. label = "Replace old hives",
  746. run_at_every_load = true,
  747. action = function(pos, node)
  748. if node.name == "bees:bees" then
  749. local timer = minetest.get_node_timer(pos)
  750. timer:start(20)
  751. end
  752. if node.name == "bees:hive" then
  753. minetest.set_node(pos, {name = "bees:hive_wild"})
  754. local meta = minetest.get_meta(pos)
  755. local inv = meta:get_inventory()
  756. inv:set_stack("queen", 1, "bees:queen")
  757. end
  758. if node.name == "bees:hive_artificial_inhabited" then
  759. minetest.set_node(pos, {name = "bees:hive_artificial"})
  760. local meta = minetest.get_meta(pos)
  761. local inv = meta:get_inventory()
  762. inv:set_stack("queen", 1, "bees:queen")
  763. local timer = minetest.get_node_timer(pos)
  764. timer:start(60)
  765. end
  766. end
  767. })
  768. --
  769. -- PIPEWORKS
  770. --
  771. if minetest.get_modpath("pipeworks") then
  772. minetest.register_node("bees:hive_industrial", {
  773. description = S("Industrial Bee Hive"),
  774. tiles = {"bees_hive_industrial.png"},
  775. paramtype2 = "facedir",
  776. groups = {
  777. snappy = 1, choppy = 2, oddly_breakable_by_hand = 2,
  778. tubedevice = 1, tubedevice_receiver = 1
  779. },
  780. sounds = default.node_sound_wood_defaults(),
  781. tube = {
  782. insert_object = function(pos, _, stack)
  783. local meta = minetest.get_meta(pos)
  784. local inv = meta:get_inventory()
  785. if stack:get_name() ~= "bees:frame_empty"
  786. or stack:get_count() > 1 then
  787. return stack
  788. end
  789. for i = 1, 8 do
  790. if inv:get_stack("frames", i):is_empty() then
  791. inv:set_stack("frames", i, stack)
  792. local timer = minetest.get_node_timer(pos)
  793. timer:start(30)
  794. meta:set_string("infotext", S("Bees are aclimating"))
  795. return ItemStack("")
  796. end
  797. end
  798. return stack
  799. end,
  800. can_insert = function(pos, _, stack)
  801. local meta = minetest.get_meta(pos)
  802. local inv = meta:get_inventory()
  803. if stack:get_name() ~= "bees:frame_empty"
  804. or stack:get_count() > 1 then
  805. return false
  806. end
  807. for i = 1, 8 do
  808. if inv:get_stack("frames", i):is_empty() then
  809. return true
  810. end
  811. end
  812. return false
  813. end,
  814. can_remove = function(_, _, stack)
  815. if stack:get_name() == "bees:frame_full" then
  816. return 1
  817. else
  818. return 0
  819. end
  820. end,
  821. input_inventory = "frames",
  822. connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
  823. },
  824. on_construct = function(pos)
  825. local meta = minetest.get_meta(pos)
  826. local inv = meta:get_inventory()
  827. meta:set_int("agressive", 1)
  828. inv:set_size("queen", 1)
  829. inv:set_size("frames", 8)
  830. meta:set_string("infotext", S("Requires Queen bee to function"))
  831. end,
  832. can_dig = function(pos)
  833. local meta = minetest.get_meta(pos)
  834. local inv = meta:get_inventory()
  835. if inv:is_empty("queen") and inv:is_empty("frames") then
  836. return true
  837. else
  838. return false
  839. end
  840. end,
  841. on_rightclick = function(pos, _, clicker)
  842. local player_name = clicker:get_player_name()
  843. if minetest.is_protected(pos, player_name) then
  844. return
  845. end
  846. minetest.show_formspec(player_name,
  847. "bees:hive_artificial",
  848. hive_artificial(pos)
  849. )
  850. local meta = minetest.get_meta(pos)
  851. local inv = meta:get_inventory()
  852. if meta:get_int("agressive") == 1
  853. and inv:contains_item("queen", "bees:queen") then
  854. stiny_player(clicker, 4)
  855. else
  856. meta:set_int("agressive", 1)
  857. end
  858. end,
  859. on_timer = function(pos)
  860. local meta = minetest.get_meta(pos)
  861. local inv = meta:get_inventory()
  862. local timer = minetest.get_node_timer(pos)
  863. if inv:contains_item("queen", "bees:queen") then
  864. if inv:contains_item("frames", "bees:frame_empty") then
  865. timer:start(30)
  866. local rad = 10
  867. local minp = {x = pos.x - rad, y = pos.y - rad, z = pos.z - rad}
  868. local maxp = {x = pos.x + rad, y = pos.y + rad, z = pos.z + rad}
  869. local flowers = minetest.find_nodes_in_area(minp, maxp, "group:flower")
  870. local progress = meta:get_int("progress")
  871. progress = progress + #flowers
  872. meta:set_int("progress", progress)
  873. if progress > 1000 then
  874. local flower = flowers[random(#flowers)]
  875. polinate_flower(flower, minetest.get_node(flower).name)
  876. local stacks = inv:get_list("frames")
  877. for k, _ in pairs(stacks) do
  878. if inv:get_stack("frames", k):get_name() == "bees:frame_empty" then
  879. meta:set_int("progress", 0)
  880. inv:set_stack("frames", k, "bees:frame_full")
  881. return
  882. end
  883. end
  884. else
  885. meta:set_string("infotext", S("progress:")
  886. .. " " .. progress .. " + " .. #flowers .. " / 1000")
  887. end
  888. else
  889. meta:set_string("infotext", S("Does not have empty frame(s)"))
  890. timer:stop()
  891. end
  892. end
  893. end,
  894. on_metadata_inventory_take = function(pos, listname)
  895. if listname == "queen" then
  896. local timer = minetest.get_node_timer(pos)
  897. local meta = minetest.get_meta(pos)
  898. meta:set_string("infotext", S("Requires Queen bee to function"))
  899. timer:stop()
  900. end
  901. end,
  902. allow_metadata_inventory_move = function(pos, from_list, _, to_list, to_index)
  903. local inv = minetest.get_meta(pos):get_inventory()
  904. if from_list == to_list then
  905. if inv:get_stack(to_list, to_index):is_empty() then
  906. return 1
  907. else
  908. return 0
  909. end
  910. else
  911. return 0
  912. end
  913. end,
  914. on_metadata_inventory_put = function(pos, listname, _, stack)
  915. local meta = minetest.get_meta(pos)
  916. local inv = meta:get_inventory()
  917. local timer = minetest.get_node_timer(pos)
  918. if listname == "queen" or listname == "frames" then
  919. meta:set_string("queen", stack:get_name())
  920. meta:set_string("infotext", S("Queen inserted, now for the empty frames"))
  921. if inv:contains_item("frames", "bees:frame_empty") then
  922. timer:start(30)
  923. meta:set_string("infotext", S("Bees are aclimating"))
  924. end
  925. end
  926. end,
  927. allow_metadata_inventory_put = function(pos, listname, index, stack)
  928. if not minetest.get_meta(pos):get_inventory():get_stack(listname, index):is_empty() then
  929. return 0
  930. end
  931. if listname == "queen" then
  932. if stack:get_name():match("bees:queen*") then
  933. return 1
  934. end
  935. elseif listname == "frames" then
  936. if stack:get_name() == ("bees:frame_empty") then
  937. return 1
  938. end
  939. end
  940. return 0
  941. end
  942. })
  943. minetest.register_craft({
  944. output = "bees:hive_industrial",
  945. recipe = {
  946. {"default:steel_ingot", "homedecor:plastic_sheeting", "default:steel_ingot"},
  947. {"pipeworks:tube_1", "bees:hive_artificial", "pipeworks:tube_1"},
  948. {"default:steel_ingot", "homedecor:plastic_sheeting", "default:steel_ingot"}
  949. }
  950. })
  951. end
  952. --
  953. -- LUCKY BLOCKS
  954. --
  955. if minetest.get_modpath("lucky_block") then
  956. local add_bees = function(pos, player)
  957. local objs = minetest.get_objects_inside_radius(pos, 15)
  958. minetest.chat_send_player(player:get_player_name(),
  959. minetest.colorize("violet", S("Bees! Bees for all!")))
  960. for n = 1, #objs do
  961. if objs[n]:is_player() then
  962. local player_pos = objs[n]:get_pos()
  963. player_pos.y = player_pos.y + 1
  964. minetest.set_node(player_pos, {name = "bees:bees"})
  965. end
  966. end
  967. end
  968. lucky_block:add_blocks({
  969. {"cus", add_bees},
  970. {"dro", {"bees:grafting_tool"}, 1},
  971. {"dro", {"bees:frame_empty"}, 2},
  972. {"dro", {"bees:queen"}, 1},
  973. {"nod", "bees:extractor"},
  974. {"dro", {"bees:frame_full"}, 2},
  975. {"dro", {"bees:bottle_honey"}, 3},
  976. {"dro", {"bees:smoker"}, 1},
  977. {"nod", "bees:hive_artificial"}
  978. })
  979. end
  980. print("[MOD] Bees Loaded")