breeder.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. -- Functions for the generator nodes.
  2. breeder = breeder or {}
  3. breeder_inactive = breeder_inactive or {}
  4. breeder_active = breeder_active or {}
  5. breeder.siren = breeder.siren or {}
  6. local BUFFER_SIZE = tech.breeder.buffer
  7. local ENERGY_TIME = tech.breeder.time
  8. local TOTAL_COOK_TIME = tech.breeder.totaltime
  9. local ENERGY_AMOUNT = tech.breeder.power
  10. local BREEDER_TIER = "mv"
  11. -- Localize for performance.
  12. local math_floor = math.floor
  13. local math_random = math.random
  14. local fuel = {}
  15. local SS_OFF = 0
  16. local SS_DANGER = 1
  17. local SS_CLEAR = 2
  18. local breeder_siren = breeder.siren
  19. local function siren_set_state(pos, state)
  20. local hpos = minetest.hash_node_position(pos)
  21. local siren = breeder_siren[hpos]
  22. if not siren then
  23. if state == SS_OFF then return end
  24. siren = {state=SS_OFF}
  25. breeder_siren[hpos] = siren
  26. end
  27. if state == SS_DANGER and siren.state ~= SS_DANGER then
  28. if siren.handle then minetest.sound_stop(siren.handle) end
  29. siren.handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_danger_loop",
  30. {pos=pos, gain=1.5, loop=true, max_hear_distance=48})
  31. siren.state = SS_DANGER
  32. elseif state == SS_CLEAR then
  33. if siren.handle then minetest.sound_stop(siren.handle) end
  34. local clear_handle = minetest.sound_play("technic_hv_nuclear_reactor_siren_clear",
  35. {pos=pos, gain=1.5, loop=false, max_hear_distance=48})
  36. siren.handle = clear_handle
  37. siren.state = SS_CLEAR
  38. minetest.after(10, function()
  39. if siren.handle ~= clear_handle then return end
  40. minetest.sound_stop(clear_handle)
  41. if breeder_siren[hpos] == siren then
  42. breeder_siren[hpos] = nil
  43. end
  44. end)
  45. elseif state == SS_OFF and siren.state ~= SS_OFF then
  46. if siren.handle then minetest.sound_stop(siren.handle) end
  47. breeder_siren[hpos] = nil
  48. end
  49. end
  50. local function siren_danger(pos, meta)
  51. meta:set_int("siren", 1)
  52. siren_set_state(pos, SS_DANGER)
  53. end
  54. local function siren_clear(pos, meta)
  55. if meta:get_int("siren") ~= 0 then
  56. siren_set_state(pos, SS_CLEAR)
  57. meta:set_int("siren", 0)
  58. end
  59. end
  60. local function get_breeder_damage(pos)
  61. local meta = minetest.get_meta(pos)
  62. local owner = meta:get_string("owner")
  63. local vm = VoxelManip()
  64. local pos1 = vector.subtract(pos, 3)
  65. local pos2 = vector.add(pos, 3)
  66. local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2)
  67. local data = vm:get_data()
  68. local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge})
  69. local c_concrete = minetest.get_content_id("concrete:concrete")
  70. local c_steel = minetest.get_content_id("stainless_steel:block")
  71. local c_lava_source = minetest.get_content_id("default:lava_source")
  72. local c_lava_flowing = minetest.get_content_id("default:lava_flowing")
  73. local concrete_layer, steel_layer, lava_layer = 0, 0, 0
  74. for z = pos1.z, pos2.z do
  75. for y = pos1.y, pos2.y do
  76. for x = pos1.x, pos2.x do
  77. local cid = data[area:index(x, y, z)]
  78. if x == pos1.x+0 or x == pos2.x-0 or
  79. y == pos1.y+0 or y == pos2.y-0 or
  80. z == pos1.z+0 or z == pos2.z-0 then
  81. if cid == c_concrete then
  82. concrete_layer = concrete_layer + 1
  83. end
  84. elseif x == pos1.x+1 or x == pos2.x-1 or
  85. y == pos1.y+1 or y == pos2.y-1 or
  86. z == pos1.z+1 or z == pos2.z-1 then
  87. if cid == c_steel then
  88. steel_layer = steel_layer + 1
  89. end
  90. elseif x == pos1.x+2 or x == pos2.x-2 or
  91. y == pos1.y+2 or y == pos2.y-2 or
  92. z == pos1.z+2 or z == pos2.z-2 then
  93. if cid == c_lava_source or cid == c_lava_flowing then
  94. lava_layer = lava_layer + 1
  95. end
  96. end
  97. end
  98. end
  99. end
  100. --minetest.chat_send_player("nhryciw1", "Checking thorium breeder reactor!")
  101. -- Debug!
  102. --if minetest.is_singleplayer() or gdac.player_is_admin(owner) then
  103. -- return 0
  104. --end
  105. if lava_layer > 24 then lava_layer = 24 end
  106. if steel_layer > 96 then steel_layer = 96 end
  107. if concrete_layer > 216 then concrete_layer = 216 end
  108. return (24 - lava_layer) +
  109. (96 - steel_layer) +
  110. (216 - concrete_layer)
  111. end
  112. local function check_environment(pos, meta)
  113. --minetest.chat_send_player("nhryciw1", "Check env!")
  114. local timer = meta:get_int("chktmr")
  115. --local active = meta:get_int("active")
  116. if timer <= 0 then
  117. local result = false
  118. local good = false
  119. local damage = get_breeder_damage(pos)
  120. if damage == 0 then
  121. good = true
  122. end
  123. --minetest.chat_send_player("nhryciw1", "Breeder reactor damage: " .. damage .. "!")
  124. if good then
  125. meta:set_string("error", "DUMMY")
  126. result = false
  127. else
  128. meta:set_string("error", "INSUFFICIENT REACTOR SHIELDING!")
  129. result = true -- Bad
  130. end
  131. -- Randomize time to next nodecheck.
  132. meta:set_int("chktmr", math_random(1*60, 3*60))
  133. return result
  134. end
  135. -- Decrement check timer.
  136. timer = timer - 1
  137. meta:set_int("chktmr", timer)
  138. -- No check performed.
  139. return nil
  140. end
  141. for k, v in ipairs({
  142. {name="inactive"},
  143. {name="active"},
  144. }) do
  145. -- Which function table are we operating on?
  146. local func = _G["breeder_" .. v.name]
  147. func.on_energy_get =
  148. function(pos, energy)
  149. local meta = minetest.get_meta(pos)
  150. local inv = meta:get_inventory()
  151. local have = inv:get_stack("out", 1):get_count()
  152. if have < energy then
  153. inv:set_stack("out", 1, ItemStack(""))
  154. func.trigger_update(pos)
  155. return have
  156. end
  157. have = have - energy
  158. inv:set_stack("out", 1, ItemStack("atomic:energy " .. have))
  159. func.trigger_update(pos)
  160. return energy
  161. end
  162. func.breeder_destroy =
  163. function(pos)
  164. minetest.after(0, function()
  165. tnt.boom(pos, {
  166. radius = 20,
  167. ignore_protection = false,
  168. ignore_on_blast = false,
  169. damage_radius = 30,
  170. disable_drops = true,
  171. })
  172. end)
  173. end
  174. func.trigger_update =
  175. function(pos)
  176. local timer = minetest.get_node_timer(pos)
  177. -- Restart timer even if already running.
  178. timer:start(1.0)
  179. end
  180. func.on_punch =
  181. function(pos, node, puncher, pointed_thing)
  182. --minetest.chat_send_player("nhryciw1", "Punched!")
  183. func.trigger_update(pos)
  184. -- Check breeder integrity.
  185. local meta = minetest.get_meta(pos)
  186. meta:set_int("chktmr", 0)
  187. func.privatize(meta)
  188. end
  189. func.compose_formspec =
  190. function(fuel_percent, item_percent)
  191. local formspec =
  192. "size[8,8.5]" ..
  193. default.formspec.get_form_colors() ..
  194. default.formspec.get_form_image() ..
  195. default.formspec.get_slot_colors() ..
  196. "label[1,0.5;Thorium Rod Compartment]" ..
  197. "list[context;fuel;1,1;3,2;]" ..
  198. "image[4,1.5;1,1;default_furnace_fire_bg.png^[lowpart:" ..
  199. (fuel_percent) .. ":default_furnace_fire_fg.png]" ..
  200. "image[5,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
  201. (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
  202. "label[6,1.0;Charge Buffer]" ..
  203. "list[context;out;6,1.5;1,1;]" ..
  204. "list[current_player;main;0,4.25;8,1;]" ..
  205. "list[current_player;main;0,5.5;8,3;8]" ..
  206. "listring[context;fuel]" ..
  207. "listring[current_player;main]" ..
  208. default.get_hotbar_bg(0, 4.25)
  209. return formspec
  210. end
  211. func.compose_infotext =
  212. function(pos, keeprunning)
  213. local meta = minetest.get_meta(pos)
  214. local eups = meta:get_int("eups")
  215. local machine_state = "Standby"
  216. if keeprunning then machine_state = "Active" end
  217. local output = math_floor(eups / ENERGY_TIME)
  218. if not keeprunning then
  219. output = 0
  220. end
  221. local infotext = "Breeder Reactor (" .. machine_state .. ")\n" ..
  222. "Output: " .. output .. " EU Per/Sec"
  223. local err = meta:get_string("error") or "DUMMY"
  224. if err ~= "" and err ~= "DUMMY" then
  225. infotext = infotext .. "\n" .. err
  226. end
  227. local damage = meta:get_int("damage")
  228. if damage > 0 then
  229. infotext = infotext .. "\nReactor damage: " .. damage .. "!"
  230. end
  231. return infotext
  232. end
  233. func.can_dig =
  234. function(pos, player)
  235. local meta = minetest.get_meta(pos)
  236. local inv = meta:get_inventory()
  237. -- The energy output inventory does not count.
  238. return inv:is_empty("fuel")
  239. end
  240. func.allow_metadata_inventory_put =
  241. function(pos, listname, index, stack, player)
  242. if minetest.test_protection(pos, player:get_player_name()) then
  243. return 0
  244. end
  245. if listname == "fuel" then
  246. local node = minetest.get_node(pos)
  247. -- Cannot put rods in an active breeder.
  248. if node.name == "breeder:inactive" and stack:get_name() == "thorium:rod" then
  249. return stack:get_count()
  250. end
  251. end
  252. return 0
  253. end
  254. func.allow_metadata_inventory_move =
  255. function(pos, from_list, from_index, to_list, to_index, count, player)
  256. return 0
  257. end
  258. func.allow_metadata_inventory_take =
  259. function(pos, listname, index, stack, player)
  260. if minetest.test_protection(pos, player:get_player_name()) then
  261. return 0
  262. end
  263. if listname == "fuel" then
  264. return stack:get_count()
  265. end
  266. return 0
  267. end
  268. func.on_timer =
  269. function(pos, elapsed)
  270. --minetest.chat_send_player("nhryciw1","# Server: On Timer! " .. minetest.get_gametime())
  271. local keeprunning = false
  272. local meta = minetest.get_meta(pos)
  273. local owner = meta:get_string("owner")
  274. local inv = meta:get_inventory()
  275. local fuellist = inv:get_list("fuel")
  276. local time = meta:get_int("time")
  277. local time2 = meta:get_float("time2")
  278. local maxtime = meta:get_int("maxtime")
  279. local maxtime2 = ENERGY_TIME
  280. local eups = meta:get_int("eups")
  281. local fuel_percent = 0
  282. local item_percent = 0
  283. local need_discharge = false
  284. -- This sets infotext, so must always call this.
  285. local bad = check_environment(pos, meta)
  286. if v.name == "active" then
  287. if bad ~= nil then
  288. if bad then
  289. meta:set_int("bad", 1)
  290. siren_danger(pos, meta)
  291. else
  292. if meta:get_int("bad") == 1 then
  293. siren_clear(pos, meta)
  294. end
  295. meta:set_int("bad", 0)
  296. end
  297. end
  298. -- Damage breeder over time if bad.
  299. if meta:get_int("bad") == 1 then
  300. local damage = meta:get_int("damage")
  301. damage = damage + 1
  302. meta:set_int("damage", damage)
  303. -- Destroy breeder after 10 minutes of continous damage.
  304. if damage > 60*10 then
  305. func.breeder_destroy(pos)
  306. return
  307. end
  308. else
  309. -- Slowly decrease damage if not bad.
  310. local damage = meta:get_int("damage")
  311. if damage > 0 then
  312. damage = damage - 1
  313. meta:set_int("damage", damage)
  314. end
  315. end
  316. else
  317. -- Slowly decrease damage when inactive.
  318. local damage = meta:get_int("damage")
  319. if damage > 0 then
  320. damage = damage - 1
  321. meta:set_int("damage", damage)
  322. end
  323. end
  324. -- Radiation damage to nearby players.
  325. if v.name == "active" then
  326. local entities = minetest.get_objects_inside_radius(pos, 3.5)
  327. for k, v in ipairs(entities) do
  328. if v:is_player() then
  329. v:set_hp(v:get_hp() - 1)
  330. -- Radiation exhausts player.
  331. sprint.set_stamina(v, 0)
  332. end
  333. end
  334. end
  335. do
  336. local stack = inv:get_stack("out", 1)
  337. --minetest.chat_send_player("nhryciw1", "# Server: " .. stack:get_count() .. " charge!")
  338. if stack:get_count() >= BUFFER_SIZE then
  339. need_discharge = true
  340. end
  341. end
  342. -- Manage fuel.
  343. if time > 0 then
  344. -- Keep burning current fuel item.
  345. time = time - 1
  346. -- Restart timer.
  347. keeprunning = true
  348. -- Generate energy.
  349. time2 = time2 + 1
  350. if time2 >= maxtime2 then
  351. if not need_discharge then
  352. local energy = "atomic:energy " .. eups
  353. if inv:room_for_item("out", energy) then
  354. inv:add_item("out", energy)
  355. else
  356. -- No room? Huh. Discharge breeder!
  357. -- Note: this can happen because charge to be added would be
  358. -- greater than stack_max. This bug was actually observed.
  359. -- It is only likely to affect high-output machines.
  360. need_discharge = true
  361. end
  362. end
  363. time2 = 0
  364. end
  365. else
  366. -- Burntime has run out, get new fuel item.
  367. if fuellist[1]:get_count() > 0 and not need_discharge then
  368. local fuel, afterfuel
  369. local is_mese = false
  370. meta:set_int("eups", 0)
  371. -- Check if we have enough fuel.
  372. local rods = 0
  373. for i = 1, 6, 1 do
  374. local stack = inv:get_stack("fuel", i)
  375. if stack:get_name() == "thorium:rod" and stack:get_count() > 0 then
  376. rods = rods + 1
  377. end
  378. end
  379. -- Try to get fuel.
  380. fuel, afterfuel = minetest.get_craft_result({
  381. method="coalfuel", width=1, items=fuellist,
  382. })
  383. if rods == 6 then
  384. -- We got uranium rods, consume them.
  385. for i = 1, 6, 1 do
  386. inv:set_stack("fuel", i, ItemStack(""))
  387. end
  388. time = TOTAL_COOK_TIME
  389. meta:set_int("maxtime", TOTAL_COOK_TIME)
  390. machines.swap_node(pos, "breeder:active")
  391. fuel_percent = 100
  392. keeprunning = true -- Restart timer.
  393. meta:set_int("eups", ENERGY_AMOUNT)
  394. else
  395. -- No valid fuel in fuel slot.
  396. machines.swap_node(pos, "breeder:inactive")
  397. --minetest.get_node_timer(pos):stop()
  398. time2 = 0
  399. end
  400. else
  401. -- No more fuel, shutdown generator.
  402. machines.swap_node(pos, "breeder:inactive")
  403. --minetest.get_node_timer(pos):stop()
  404. meta:set_int("eups", 0)
  405. time2 = 0
  406. end
  407. end
  408. -- Discharge energy into the network.
  409. if need_discharge then
  410. --minetest.chat_send_player("nhryciw1", "# Server: Discharging breeder reactor!")
  411. local energy = inv:get_stack("out", 1)
  412. local old = energy:get_count()
  413. energy:set_count(net2.put_energy(pos, owner, old, BREEDER_TIER))
  414. inv:set_stack("out", 1, energy)
  415. if energy:get_count() < old then
  416. -- If we succeeded in discharging energy, keep doing so.
  417. -- Otherwise, batteries are full.
  418. keeprunning = true
  419. end
  420. end
  421. -- If generator is no longer producing energy,
  422. -- unload the buffered energy.
  423. if not keeprunning then
  424. local energy = inv:get_stack("out", 1)
  425. energy:set_count(net2.put_energy(pos, owner, energy:get_count(), BREEDER_TIER))
  426. inv:set_stack("out", 1, energy)
  427. end
  428. -- Update infotext & formspec.
  429. meta:set_int("time", time)
  430. meta:set_float("time2", time2)
  431. fuel_percent = math_floor(time / maxtime * 100)
  432. item_percent = math_floor(time2 / maxtime2 * 100)
  433. meta:set_string("infotext", func.compose_infotext(pos, keeprunning))
  434. meta:set_string("formspec", func.compose_formspec(fuel_percent, item_percent))
  435. -- Determine mode (active or sleep) and set timer accordingly.
  436. if keeprunning then
  437. minetest.get_node_timer(pos):start(1.0)
  438. else
  439. -- Slow down timer during sleep periods to reduce load.
  440. minetest.get_node_timer(pos):start(math_random(1, 3*60))
  441. end
  442. end
  443. --minetest.chat_send_all("breeder.on_timer registered")
  444. func.on_blast =
  445. function(pos)
  446. local drops = {}
  447. -- Ignore contents of fuel inventory.
  448. minetest.remove_node(pos)
  449. if v.name == "active" then
  450. func.breeder_destroy(pos)
  451. else
  452. -- Only save breeder if it wasn't active.
  453. drops[#drops+1] = "breeder:inactive"
  454. end
  455. return drops
  456. end
  457. --minetest.chat_send_all("breeder.on_blast registered")
  458. func.on_construct =
  459. function(pos)
  460. local meta = minetest.get_meta(pos)
  461. local inv = meta:get_inventory()
  462. meta:set_string("infotext", func.compose_infotext(pos, false))
  463. meta:set_string("formspec", func.compose_formspec(0, 0))
  464. --minetest.chat_send_player("nhryciw1", "Breeder reactor constructed!")
  465. inv:set_size("fuel", 6)
  466. inv:set_size("out", 1)
  467. meta:set_string("owner", "DUMMY")
  468. meta:set_string("error", "DUMMY")
  469. meta:set_string("nodename", "DUMMY")
  470. meta:set_int("siren", 0)
  471. meta:set_int("chktmr", 0)
  472. meta:set_int("eups", 0)
  473. meta:set_int("damage", 0)
  474. meta:set_int("time", 0)
  475. meta:set_int("maxtime", 0)
  476. meta:set_int("bad", 0)
  477. meta:set_float("time2", 0.0)
  478. func.privatize(meta)
  479. end
  480. --minetest.chat_send_all("breeder.on_construct registered")
  481. func.privatize =
  482. function(meta)
  483. meta:mark_as_private({
  484. "nodename", "bad", "time2", "maxtime", "siren", "owner",
  485. "chktmr", "error", "eups", "damage", "time",
  486. })
  487. end
  488. func.on_destruct =
  489. function(pos)
  490. local meta = minetest.get_meta(pos)
  491. siren_set_state(pos, SS_OFF)
  492. net2.clear_caches(pos, meta:get_string("owner"), BREEDER_TIER)
  493. nodestore.del_node(pos)
  494. if v.name == "active" then
  495. func.breeder_destroy(pos)
  496. end
  497. end
  498. func.after_place_node =
  499. function(pos, placer, itemstack, pointed_thing)
  500. local meta = minetest.get_meta(pos)
  501. local node = minetest.get_node(pos)
  502. local owner = placer:get_player_name()
  503. meta:set_string("nodename", node.name)
  504. meta:set_string("owner", owner)
  505. net2.clear_caches(pos, owner, BREEDER_TIER)
  506. nodestore.add_node(pos)
  507. end
  508. func.on_metadata_inventory_move =
  509. function(pos)
  510. func.trigger_update(pos)
  511. end
  512. func.on_metadata_inventory_put =
  513. function(pos)
  514. func.trigger_update(pos)
  515. end
  516. func.on_metadata_inventory_take =
  517. function(pos, listname, index, stack, player)
  518. func.trigger_update(pos)
  519. end
  520. end
  521. --i cannot for the life of me figure out why the normal reactor works without this, but it does.
  522. breeder.run_once = false
  523. if not breeder.run_once then
  524. for k, v in ipairs({
  525. {name="inactive", light=0},
  526. {name="active", light=14},
  527. }) do
  528. -- Which function table are we operating on?
  529. local func = _G["breeder_" .. v.name]
  530. minetest.register_node(":breeder:" .. v.name, {
  531. description = "Thorium Breeder Reactor Core\n\nConnects to an MV power-network.\nGenerates a large amount of power.\nExplosion danger, requires shielding!",
  532. tiles = {"reactor_core.png"},
  533. groups = utility.dig_groups("machine", {immovable=1}),
  534. paramtype2 = "facedir",
  535. is_ground_content = false,
  536. sounds = default.node_sound_metal_defaults(),
  537. drop = "breeder:inactive",
  538. light_source = v.light,
  539. on_energy_get = function(...)
  540. return breeder.on_energy_get(...) end,
  541. on_rotate = function(...)
  542. return screwdriver.rotate_simple(...) end,
  543. on_punch = function(...)
  544. return func.on_punch(...) end,
  545. can_dig = function(...)
  546. return func.can_dig(...) end,
  547. on_timer = function(...)
  548. return func.on_timer(...) end,
  549. on_construct = function(...)
  550. return func.on_construct(...) end,
  551. on_destruct = function(...)
  552. return func.on_destruct(...) end,
  553. after_place_node = function(...)
  554. return func.after_place_node(...) end,
  555. on_blast = function(...)
  556. return func.on_blast(...) end,
  557. on_metadata_inventory_move = function(...)
  558. return func.on_metadata_inventory_move(...) end,
  559. on_metadata_inventory_put = function(...)
  560. return func.on_metadata_inventory_put(...) end,
  561. on_metadata_inventory_take = function(...)
  562. return func.on_metadata_inventory_take(...) end,
  563. allow_metadata_inventory_put = function(...)
  564. return func.allow_metadata_inventory_put(...) end,
  565. allow_metadata_inventory_move = function(...)
  566. return func.allow_metadata_inventory_move(...) end,
  567. allow_metadata_inventory_take = function(...)
  568. return func.allow_metadata_inventory_take(...) end,
  569. })
  570. end
  571. --minetest.chat_send_all("node registered")
  572. minetest.register_craft({
  573. output = 'breeder:inactive',
  574. recipe = {
  575. {'techcrafts:carbon_plate', 'default:obsidian_glass', 'techcrafts:carbon_plate'},
  576. {'techcrafts:composite_plate', 'gen2:mv_inactive', 'techcrafts:composite_plate'},
  577. {'stainless_steel:ingot', 'geo2:lv_inactive', 'stainless_steel:ingot'},
  578. }
  579. })
  580. local c = "breeder:core"
  581. local f = machines.modpath .. "/breeder.lua"
  582. reload.register_file(c, f, false)
  583. breeder.run_once = true
  584. end