v2.lua 17 KB

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