v2.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. grind2 = grind2 or {}
  2. grind2.modpath = minetest.get_modpath("grinder")
  3. local MACHINE_NAME = "Grinder"
  4. local MACHINE_DESC = "This grinds things.\nCan burn mese for fuel when off-grid.\nAlternatively, connect to a power-network."
  5. local MACHINE_FUEL_EU_PER_SEC = 80
  6. local RECIPE_TYPE = "grinding"
  7. grind2_lv = grind2_lv or {}
  8. grind2_mv = grind2_mv or {}
  9. for j, t in ipairs({
  10. {tier="lv", up="LV", speed=2.0, level=1, buffer=1000, demand=200},
  11. {tier="mv", up="MV", speed=0.6, level=2, buffer=6000, demand=300},
  12. }) do
  13. -- Which function table are we operating on?
  14. local func = _G["grind2_" .. t.tier]
  15. -- Read values from balancing table.
  16. local techname = "grinder_" .. t.tier
  17. t.speed = tech[techname].timecut
  18. t.buffer = tech[techname].buffer
  19. t.demand = tech[techname].demand
  20. func.get_formspec_defaults = function()
  21. local str =
  22. default.gui_bg ..
  23. default.gui_bg_img ..
  24. default.gui_slots
  25. return str
  26. end
  27. func.formspec_active = function(fuel_percent, item_percent)
  28. local x1 = 3.5
  29. local x2 = 4.5
  30. local x3 = 5.5
  31. local x4 = 0.5
  32. if t.level <= 1 then
  33. x1 = 3
  34. x2 = 4
  35. x3 = 5
  36. x4 = 1
  37. end
  38. local formspec =
  39. "size[8,8.5]" ..
  40. func.get_formspec_defaults() ..
  41. "label[" .. x1 .. ",0;Fuel & Input]" ..
  42. "list[context;src;" .. x1 .. ",0.5;1,1;]" ..
  43. "list[context;fuel;" .. x1 .. ",2.5;1,1;]" ..
  44. "image[" .. x1 .. ",1.5;1,1;machine_progress_bg.png^[lowpart:" ..
  45. (fuel_percent) .. ":machine_progress_fg.png]" ..
  46. "image[" .. x2 .. ",1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:" ..
  47. (item_percent) .. ":gui_furnace_arrow_fg.png^[transformR270]" ..
  48. "label[" .. x3 .. ",0.46;Destination]" ..
  49. "list[context;dst;" .. x3 .. ",0.96;2,2;]" ..
  50. "list[current_player;main;0,4.25;8,1;]" ..
  51. "list[current_player;main;0,5.5;8,3;8]"
  52. if t.level > 1 then
  53. formspec = formspec ..
  54. "label[0.5,0;Upgrades]" ..
  55. "list[context;upg;0.5,0.5;2,1;]"
  56. end
  57. formspec = formspec ..
  58. "label[" .. x4 .. ",2;Buffer]" ..
  59. "list[context;buffer;" .. x4 .. ",2.5;1,1;]" ..
  60. "listring[context;dst]" ..
  61. "listring[current_player;main]" ..
  62. "listring[context;src]" ..
  63. "listring[current_player;main]" ..
  64. "listring[context;fuel]"..
  65. "listring[current_player;main]"..
  66. default.get_hotbar_bg(0, 4.25)
  67. return formspec
  68. end
  69. func.formspec_inactive = function()
  70. return func.formspec_active(0, 0)
  71. end
  72. func.on_punch =
  73. function(pos, node, puncher, pointed_thing)
  74. func.trigger_update(pos)
  75. end
  76. func.trigger_update =
  77. function(pos)
  78. local timer = minetest.get_node_timer(pos)
  79. -- Start timer even if already running.
  80. timer:start(1.0)
  81. end
  82. func.can_dig = function(pos, player)
  83. local meta = minetest.get_meta(pos)
  84. local inv = meta:get_inventory()
  85. if t.level > 1 then
  86. return inv:is_empty("fuel") and
  87. inv:is_empty("dst") and
  88. inv:is_empty("src") and
  89. inv:is_empty("upg")
  90. else
  91. return inv:is_empty("fuel") and
  92. inv:is_empty("dst") and
  93. inv:is_empty("src")
  94. -- No upgrade slots.
  95. end
  96. end
  97. func.get_speed =
  98. function(pos, meta, inv)
  99. if t.level <= 1 then
  100. return t.speed
  101. end
  102. local clus = utility.inventory_count_items(inv, "upg", "techcrafts:control_logic_unit")
  103. if clus == 1 then
  104. return (t.speed*0.8)
  105. elseif clus == 2 then
  106. return (t.speed*0.7)
  107. end
  108. return t.speed
  109. end
  110. func.get_demand =
  111. function(pos, meta, inv)
  112. if t.level <= 1 then
  113. return t.demand
  114. end
  115. local bats = utility.inventory_count_items(inv, "upg", "battery:battery")
  116. if bats == 1 then
  117. return math.floor(t.demand*0.8)
  118. elseif bats == 2 then
  119. return math.floor(t.demand*0.7)
  120. end
  121. return t.demand
  122. end
  123. func.has_public_access =
  124. function(pos)
  125. if t.level <= 1 then
  126. return
  127. end
  128. local meta = minetest.get_meta(pos)
  129. local inv = meta:get_inventory()
  130. local s1 = inv:get_stack("upg", 1)
  131. if s1:get_count() > 0 then
  132. if minetest.get_item_group(s1:get_name(), "chest") > 0 then
  133. return true
  134. end
  135. end
  136. local s2 = inv:get_stack("upg", 2)
  137. if s2:get_count() > 0 then
  138. if minetest.get_item_group(s2:get_name(), "chest") > 0 then
  139. return true
  140. end
  141. end
  142. end
  143. func.allow_metadata_inventory_put =
  144. function(pos, listname, index, stack, player)
  145. local pname = player:get_player_name()
  146. local public = func.has_public_access(pos)
  147. local protected = false
  148. if minetest.test_protection(pos, pname) then
  149. protected = true
  150. end
  151. if listname == "fuel" and (not protected or public) then
  152. if minetest.get_craft_result({method="mesefuel", width=1, items={stack}}).time ~= 0 then
  153. return stack:get_count()
  154. end
  155. elseif listname == "src" and (not protected or public)then
  156. return stack:get_count()
  157. elseif t.level > 1 and listname == "upg" and not protected then
  158. if minetest.get_item_group(stack:get_name(), "chest") > 0 then
  159. return stack:get_count()
  160. elseif stack:get_name() == "battery:battery" then
  161. return stack:get_count()
  162. elseif stack:get_name() == "techcrafts:control_logic_unit" then
  163. return stack:get_count()
  164. end
  165. -- Enables testing.
  166. --elseif listname == "buffer" and stack:get_name() == "atomic:energy" then
  167. -- return stack:get_count()
  168. end
  169. return 0
  170. end
  171. func.allow_metadata_inventory_move =
  172. function(pos, from_list, from_index, to_list, to_index, count, player)
  173. local pname = player:get_player_name()
  174. local public = func.has_public_access(pos)
  175. local protected = false
  176. if minetest.test_protection(pos, pname) then
  177. protected = true
  178. end
  179. if (from_list == "upg" or to_list == "upg") and protected and t.level > 1 then
  180. return 0
  181. end
  182. if not protected or public then
  183. if from_list == "buffer" or to_list == "buffer" then
  184. return 0
  185. end
  186. if from_list == to_list then
  187. return count
  188. end
  189. end
  190. return 0
  191. end
  192. func.allow_metadata_inventory_take =
  193. function(pos, listname, index, stack, player)
  194. local pname = player:get_player_name()
  195. local public = func.has_public_access(pos)
  196. local protected = false
  197. if minetest.test_protection(pos, pname) then
  198. protected = true
  199. end
  200. if listname == "fuel" and (not protected or public) then
  201. return stack:get_count()
  202. elseif listname == "dst" and (not protected or public) then
  203. return stack:get_count()
  204. elseif listname == "upg" and not protected and t.level > 1 then
  205. return stack:get_count()
  206. elseif listname == "src" and (not protected or public) then
  207. return stack:get_count()
  208. end
  209. return 0
  210. end
  211. func.on_timer = function(pos, elapsed)
  212. --[[
  213. 1) Check if we have cookable content:
  214. a) If YES, goto 'on cook content' (step 2).
  215. b) If NO, stop machine, end func.
  216. 2) On cook content:
  217. a) Check if item fully cooked (cooking time >= needed time).
  218. 1) If NO, goto 'check if we have buffered energy'.
  219. 2) If YES, put result into dest, decrement source, end func.
  220. a) Set machine active.
  221. b) Check if we have needed amount of buffered energy.
  222. 1) If YES, increment cooktime, consume energy, end func.
  223. a) Set machine active.
  224. 2) If NO, get energy (on get energy). Send wanted energy.
  225. 3) On get energy (buffer should be empty or nearly so):
  226. a) Check if we can get energy from fuel.
  227. 1) If YES, consume fuel to buffered energy, goto 'got enough energy?'
  228. 2) If NO, goto 'get energy from network'.
  229. b) Check if we can get energy from network.
  230. 1) If YES, get energy from network, goto 'got enough energy?'.
  231. 2) If NO (network exhausted/buffer full), stop machine, end func.
  232. 4) Did we get enough energy? (Received wanted energy from step 2b2.)
  233. a) If YES, end func.
  234. 1) Set machine active.
  235. b) If NO, goto 'on get energy' (trying again).
  236. 5) End func.
  237. a) Check if machine is active.
  238. 1) If YES, keep running.
  239. 2) If NO, enter sleep mode.
  240. --]]
  241. local meta = minetest.get_meta(pos)
  242. local inv = meta:get_inventory()
  243. local wantedenergy = 0
  244. local keeprunning = false
  245. local demand = func.get_demand(pos, meta, inv)
  246. local speed = func.get_speed(pos, meta, inv)
  247. -- Check if we have cookable content.
  248. local srclist = inv:get_list("src")
  249. local cookable = true
  250. local cooked, aftercooked = minetest.get_craft_result({
  251. method = RECIPE_TYPE, width = 1, items = srclist})
  252. if cooked.time == 0 then
  253. cookable = false
  254. end
  255. -- If we have cookable content, goto 'on cook content'.
  256. if cookable then
  257. -- If total energy time wasn't recorded yet, record it.
  258. if meta:get_int("fueltotaltime") == 0 then
  259. local energy = inv:get_stack("buffer", 1):get_count()
  260. meta:set_int("fueltotaltime", math.floor(energy/demand))
  261. end
  262. goto on_cook
  263. else
  264. -- Stop machine.
  265. keeprunning = false
  266. goto end_func
  267. end
  268. -- On cook content.
  269. ::on_cook::
  270. do
  271. -- Check if item is fully cooked.
  272. if meta:get_float("srctime") >= cooked.time then
  273. -- Place result in dst list if possible
  274. if inv:room_for_item("dst", cooked.item) then
  275. inv:add_item("dst", cooked.item)
  276. inv:set_stack("src", 1, aftercooked.items[1])
  277. meta:set_float("srctime", 0)
  278. -- Check if there are still items in the source slot.
  279. local srclist = inv:get_list("src")
  280. local cooked, aftercooked = minetest.get_craft_result({
  281. method = RECIPE_TYPE, width = 1, items = srclist})
  282. if cooked.time == 0 then
  283. -- No more items? Stop machine.
  284. meta:set_int("fueltotaltime", 0)
  285. keeprunning = false
  286. goto end_func
  287. else
  288. -- Set machine active.
  289. keeprunning = true
  290. goto end_func
  291. end
  292. else
  293. -- Stop machine, no room!
  294. meta:set_int("fueltotaltime", 0)
  295. keeprunning = false
  296. goto end_func
  297. end
  298. else
  299. -- Check if we have buffered energy.
  300. goto check_buffered_energy
  301. end
  302. end
  303. -- Check if we have buffered energy.
  304. ::check_buffered_energy::
  305. do
  306. local energy = inv:get_stack("buffer", 1)
  307. if energy:get_count() >= demand then
  308. -- Increment cooktime.
  309. meta:set_float("srctime", meta:get_float("srctime") + 1/speed)
  310. energy:take_item(math.floor(demand/speed))
  311. inv:set_stack("buffer", 1, energy)
  312. -- Set machine active.
  313. keeprunning = true
  314. goto end_func
  315. else
  316. -- Goto 'on get energy'. Send wanted amount of energy.
  317. wantedenergy = demand
  318. goto on_get_energy
  319. end
  320. end
  321. -- On get energy.
  322. ::on_get_energy::
  323. do
  324. -- Check if we can get energy from fuel.
  325. local fuellist = inv:get_list("fuel")
  326. local fuel, afterfuel = minetest.get_craft_result({
  327. method = "mesefuel", width = 1, items = fuellist})
  328. if fuel.time > 0 then
  329. local old = inv:get_stack("buffer", 1):get_count()
  330. local energy = old + math.floor(fuel.time * MACHINE_FUEL_EU_PER_SEC)
  331. meta:set_int("fueltotaltime", math.floor(energy/demand))
  332. inv:set_stack("buffer", 1, "atomic:energy " .. energy)
  333. inv:set_stack("fuel", 1, afterfuel.items[1])
  334. goto check_got_enough_energy
  335. else
  336. goto get_energy_from_network
  337. end
  338. end
  339. -- Check if we can get energy from network.
  340. ::get_energy_from_network::
  341. do
  342. local current = inv:get_stack("buffer", 1)
  343. if current:get_count() < t.buffer then
  344. local owner = meta:get_string("owner")
  345. local get_amount = t.buffer
  346. local energy = net2.get_energy(pos, owner, get_amount, t.tier)
  347. if energy > 0 then
  348. local old = inv:get_stack("buffer", 1):get_count()
  349. energy = energy + old
  350. meta:set_int("fueltotaltime", math.floor(energy/demand))
  351. inv:set_stack("buffer", 1, "atomic:energy " .. energy)
  352. goto check_got_enough_energy
  353. else
  354. -- Stop machine (network exhausted).
  355. keeprunning = false
  356. goto end_func
  357. end
  358. else
  359. -- Stop machine (buffer full).
  360. keeprunning = false
  361. goto end_func
  362. end
  363. end
  364. -- Check if we got enough energy.
  365. ::check_got_enough_energy::
  366. do
  367. local energy = inv:get_stack("buffer", 1)
  368. if energy:get_count() >= wantedenergy then
  369. keeprunning = true
  370. goto end_func
  371. else
  372. -- Keep trying to get energy.
  373. goto on_get_energy
  374. end
  375. end
  376. -- End func.
  377. ::end_func::
  378. do
  379. if keeprunning then
  380. local itempercent = 0
  381. if cookable then
  382. itempercent = math.floor(meta:get_float("srctime") / cooked.time * 100)
  383. end
  384. local fueltime = math.floor(inv:get_stack("buffer", 1):get_count()/demand)
  385. local fueltotaltime = meta:get_int("fueltotaltime")
  386. local fuelpercent = math.floor(fueltime / fueltotaltime * 100)
  387. local eu_demand = math.floor(demand/speed)
  388. local infotext = t.up .. " " .. MACHINE_NAME .. " (Active)\n" ..
  389. "Demand: " .. eu_demand .. " EU Per/Sec"
  390. local formspec = func.formspec_active(fuelpercent, itempercent)
  391. meta:set_string("infotext", infotext)
  392. meta:set_string("formspec", formspec)
  393. machines.swap_node(pos, "grind2:" .. t.tier .. "_active")
  394. minetest.get_node_timer(pos):start(1.0)
  395. else
  396. local infotext = t.up .. " " .. MACHINE_NAME .. " (Standby)\n" ..
  397. "Demand: 0 EU Per/Sec"
  398. local formspec = func.formspec_inactive()
  399. meta:set_string("infotext", infotext)
  400. meta:set_string("formspec", formspec)
  401. meta:set_int("fueltotaltime", 0)
  402. meta:set_float("srctime", 0)
  403. machines.swap_node(pos, "grind2:" .. t.tier .. "_inactive")
  404. minetest.get_node_timer(pos):start(math.random(1, 3*60))
  405. end
  406. end
  407. end
  408. func.on_construct =
  409. function(pos)
  410. end
  411. func.on_destruct =
  412. function(pos)
  413. local meta = minetest.get_meta(pos)
  414. local owner = meta:get_string("owner")
  415. net2.clear_caches(pos, owner, t.tier)
  416. nodestore.del_node(pos)
  417. end
  418. func.after_place_node =
  419. function(pos, placer, itemstack, pointed_thing)
  420. local owner = placer:get_player_name()
  421. local meta = minetest.get_meta(pos)
  422. local node = minetest.get_node(pos)
  423. local inv = meta:get_inventory()
  424. meta:set_string("owner", owner)
  425. meta:set_string("nodename", node.name)
  426. inv:set_size('src', 1)
  427. inv:set_size('fuel', 1)
  428. inv:set_size('dst', 4)
  429. if t.level > 1 then
  430. inv:set_size('upg', 2)
  431. end
  432. inv:set_size('buffer', 1)
  433. meta:set_string("formspec", func.formspec_inactive())
  434. meta:set_string("infotext", t.up .. " " .. MACHINE_NAME .. " (Standby)\n" ..
  435. "Demand: 0 EU Per/Sec")
  436. nodestore.add_node(pos)
  437. net2.clear_caches(pos, owner, t.tier)
  438. local timer = minetest.get_node_timer(pos)
  439. timer:start(1.0)
  440. end
  441. func.on_metadata_inventory_move =
  442. function(pos)
  443. func.trigger_update(pos)
  444. end
  445. func.on_metadata_inventory_put =
  446. function(pos)
  447. func.trigger_update(pos)
  448. end
  449. func.on_metadata_inventory_take =
  450. function(pos)
  451. func.trigger_update(pos)
  452. end
  453. func.on_blast = function(pos)
  454. local drops = {}
  455. default.get_inventory_drops(pos, "src", drops)
  456. default.get_inventory_drops(pos, "fuel", drops)
  457. default.get_inventory_drops(pos, "dst", drops)
  458. if t.level > 1 then
  459. default.get_inventory_drops(pos, "upg", drops)
  460. end
  461. drops[#drops+1] = "grind2:" .. t.tier .. "_inactive"
  462. minetest.remove_node(pos)
  463. return drops
  464. end
  465. end
  466. if not grind2.run_once then
  467. for j, t in ipairs({
  468. {tier="lv", up="LV"},
  469. {tier="mv", up="MV"},
  470. }) do
  471. -- Which function table are we operating on?
  472. local func = _G["grind2_" .. t.tier]
  473. for k, v in ipairs({
  474. {name="inactive", light=0, tile="grinder_" .. t.tier .. "_front.png"},
  475. {name="active", light=8, tile="grinder_" .. t.tier .. "_front_active.png"},
  476. }) do
  477. minetest.register_node(":grind2:" .. t.tier .. "_" .. v.name, {
  478. description = t.up .. " " .. MACHINE_NAME .. "\n\n" .. MACHINE_DESC,
  479. tiles = {
  480. "grinder_" .. t.tier .. "_top.png", "grinder_" .. t.tier .. "_bottom.png",
  481. "grinder_" .. t.tier .. "_side.png", "grinder_" .. t.tier .. "_side.png",
  482. "grinder_" .. t.tier .. "_side.png", v.tile,
  483. },
  484. paramtype2 = "facedir",
  485. groups = utility.dig_groups("machine"),
  486. light_source = v.light,
  487. is_ground_content = false,
  488. sounds = default.node_sound_metal_defaults(),
  489. drop = "grind2:" .. t.tier .. "_inactive",
  490. on_rotate = function(...)
  491. return screwdriver.rotate_simple(...) end,
  492. can_dig = function(...)
  493. return func.can_dig(...) end,
  494. on_timer = function(...)
  495. return func.on_timer(...) end,
  496. on_construct = function(...)
  497. return func.on_construct(...) end,
  498. on_destruct = function(...)
  499. return func.on_destruct(...) end,
  500. on_blast = function(...)
  501. return func.on_blast(...) end,
  502. on_punch = function(...)
  503. return func.on_punch(...) end,
  504. after_place_node = function(...)
  505. return func.after_place_node(...) end,
  506. on_metadata_inventory_move = function(...)
  507. return func.on_metadata_inventory_move(...) end,
  508. on_metadata_inventory_put = function(...)
  509. return func.on_metadata_inventory_put(...) end,
  510. on_metadata_inventory_take = function(...)
  511. return func.on_metadata_inventory_take(...) end,
  512. allow_metadata_inventory_put = function(...)
  513. return func.allow_metadata_inventory_put(...) end,
  514. allow_metadata_inventory_move = function(...)
  515. return func.allow_metadata_inventory_move(...) end,
  516. allow_metadata_inventory_take = function(...)
  517. return func.allow_metadata_inventory_take(...) end,
  518. })
  519. end
  520. end
  521. minetest.register_alias("grind2:inactive", "grind2:mv_inactive")
  522. minetest.register_alias("grind2:active", "grind2:mv_active")
  523. local c = "grind2:core"
  524. local f = grind2.modpath .. "/v2.lua"
  525. reload.register_file(c, f, false)
  526. grind2.run_once = true
  527. end