init.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. local EEPROM_SIZE = 255
  2. local microc_rules = {}
  3. local yc = {}
  4. for a = 0, 1 do
  5. for b = 0, 1 do
  6. for c = 0, 1 do
  7. for d = 0, 1 do
  8. local nodename = "mesecons_microcontroller:microcontroller"..tostring(d)..tostring(c)..tostring(b)..tostring(a)
  9. local top = "jeija_microcontroller_top.png"
  10. if tostring(a) == "1" then
  11. top = top.."^jeija_microcontroller_LED_A.png"
  12. end
  13. if tostring(b) == "1" then
  14. top = top.."^jeija_microcontroller_LED_B.png"
  15. end
  16. if tostring(c) == "1" then
  17. top = top.."^jeija_microcontroller_LED_C.png"
  18. end
  19. if tostring(d) == "1" then
  20. top = top.."^jeija_microcontroller_LED_D.png"
  21. end
  22. local groups
  23. if tostring(d)..tostring(c)..tostring(b)..tostring(a) ~= "0000" then
  24. groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon = 3, overheat = 1}
  25. else
  26. groups = {dig_immediate=2, mesecon = 3, overheat = 1}
  27. end
  28. local rules={}
  29. if (a == 1) then table.insert(rules, {x = -1, y = 0, z = 0}) end
  30. if (b == 1) then table.insert(rules, {x = 0, y = 0, z = 1}) end
  31. if (c == 1) then table.insert(rules, {x = 1, y = 0, z = 0}) end
  32. if (d == 1) then table.insert(rules, {x = 0, y = 0, z = -1}) end
  33. local input_rules={}
  34. if (a == 0) then table.insert(input_rules, {x = -1, y = 0, z = 0, name = "A"}) end
  35. if (b == 0) then table.insert(input_rules, {x = 0, y = 0, z = 1, name = "B"}) end
  36. if (c == 0) then table.insert(input_rules, {x = 1, y = 0, z = 0, name = "C"}) end
  37. if (d == 0) then table.insert(input_rules, {x = 0, y = 0, z = -1, name = "D"}) end
  38. microc_rules[nodename] = rules
  39. local mesecons = {effector =
  40. {
  41. rules = input_rules,
  42. action_change = function (pos, node, rulename, newstate)
  43. yc.update_real_portstates(pos, node, rulename, newstate)
  44. yc.update(pos)
  45. end
  46. }}
  47. if nodename ~= "mesecons_microcontroller:microcontroller0000" then
  48. mesecons.receptor = {
  49. state = mesecon.state.on,
  50. rules = rules
  51. }
  52. end
  53. minetest.register_node(nodename, {
  54. description = "Microcontroller",
  55. drawtype = "nodebox",
  56. tiles = {
  57. top,
  58. "jeija_microcontroller_bottom.png",
  59. "jeija_microcontroller_sides.png",
  60. "jeija_microcontroller_sides.png",
  61. "jeija_microcontroller_sides.png",
  62. "jeija_microcontroller_sides.png"
  63. },
  64. sunlight_propagates = true,
  65. paramtype = "light",
  66. is_ground_content = false,
  67. walkable = true,
  68. groups = groups,
  69. drop = "mesecons_microcontroller:microcontroller0000 1",
  70. selection_box = {
  71. type = "fixed",
  72. fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
  73. },
  74. node_box = {
  75. type = "fixed",
  76. fixed = {
  77. { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
  78. { -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board
  79. { -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC
  80. }
  81. },
  82. on_construct = function(pos)
  83. local meta = minetest.get_meta(pos)
  84. meta:set_string("code", "")
  85. meta:set_string("formspec", "size[9,2.5]"..
  86. "field[0.256,-0.2;9,2;code;Code:;]"..
  87. "button[0 ,0.2;1.5,3;band;AND]"..
  88. "button[1.5,0.2;1.5,3;bxor;XOR]"..
  89. "button[3 ,0.2;1.5,3;bnot;NOT]"..
  90. "button[4.5,0.2;1.5,3;bnand;NAND]"..
  91. "button[6 ,0.2;1.5,3;btflop;T-Flop]"..
  92. "button[7.5,0.2;1.5,3;brsflop;RS-Flop]"..
  93. "button_exit[3.5,1;2,3;program;Program]")
  94. meta:set_string("infotext", "Unprogrammed Microcontroller")
  95. local r = ""
  96. for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0"
  97. meta:set_string("eeprom", r)
  98. end,
  99. on_receive_fields = function(pos, formanme, fields, sender)
  100. local player_name = sender:get_player_name()
  101. if minetest.is_protected(pos, player_name) and
  102. not minetest.check_player_privs(player_name, {protection_bypass=true}) then
  103. minetest.record_protection_violation(pos, player_name)
  104. return
  105. end
  106. local meta = minetest.get_meta(pos)
  107. if fields.band then
  108. fields.code = "sbi(C, A&B) :A and B are inputs, C is output"
  109. elseif fields.bxor then
  110. fields.code = "sbi(C, A~B) :A and B are inputs, C is output"
  111. elseif fields.bnot then
  112. fields.code = "sbi(B, !A) :A is input, B is output"
  113. elseif fields.bnand then
  114. fields.code = "sbi(C, !A|!B) :A and B are inputs, C is output"
  115. elseif fields.btflop then
  116. fields.code = "if(A)sbi(1,1);if(!A&#1)sbi(B,!B)sbi(1,0); if(C)off(B,1); :A is input, B is output (Q), C is reset, toggles with falling edge"
  117. elseif fields.brsflop then
  118. fields.code = "if(A)on(C);if(B)off(C); :A is S (Set), B is R (Reset), C is output (R dominates)"
  119. end
  120. if fields.code == nil then return end
  121. meta:set_string("code", fields.code)
  122. meta:set_string("formspec", "size[9,2.5]"..
  123. "field[0.256,-0.2;9,2;code;Code:;"..minetest.formspec_escape(fields.code).."]"..
  124. "button[0 ,0.2;1.5,3;band;AND]"..
  125. "button[1.5,0.2;1.5,3;bxor;XOR]"..
  126. "button[3 ,0.2;1.5,3;bnot;NOT]"..
  127. "button[4.5,0.2;1.5,3;bnand;NAND]"..
  128. "button[6 ,0.2;1.5,3;btflop;T-Flop]"..
  129. "button[7.5,0.2;1.5,3;brsflop;RS-Flop]"..
  130. "button_exit[3.5,1;2,3;program;Program]")
  131. meta:set_string("infotext", "Programmed Microcontroller")
  132. yc.reset (pos)
  133. yc.update(pos)
  134. end,
  135. sounds = default.node_sound_stone_defaults(),
  136. mesecons = mesecons,
  137. after_dig_node = function (pos, node)
  138. rules = microc_rules[node.name]
  139. mesecon.receptor_off(pos, rules)
  140. end,
  141. on_blast = mesecon.on_blastnode,
  142. })
  143. end
  144. end
  145. end
  146. end
  147. if minetest.get_modpath("mesecons_luacontroller") then
  148. minetest.register_craft({
  149. type = "shapeless",
  150. output = "mesecons_microcontroller:microcontroller0000",
  151. recipe = {"mesecons_luacontroller:luacontroller0000"},
  152. })
  153. minetest.register_craft({
  154. type = "shapeless",
  155. output = "mesecons_luacontroller:luacontroller0000",
  156. recipe = {"mesecons_microcontroller:microcontroller0000"},
  157. })
  158. else
  159. minetest.register_craft({
  160. output = 'craft "mesecons_microcontroller:microcontroller0000" 2',
  161. recipe = {
  162. {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
  163. {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
  164. {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''},
  165. }
  166. })
  167. end
  168. yc.reset = function(pos)
  169. yc.action(pos, {a=false, b=false, c=false, d=false})
  170. local meta = minetest.get_meta(pos)
  171. meta:set_int("afterid", 0)
  172. local r = ""
  173. for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0"
  174. meta:set_string("eeprom", r)
  175. end
  176. yc.update = function(pos)
  177. local meta = minetest.get_meta(pos)
  178. if (mesecon.do_overheat(pos)) then
  179. minetest.remove_node(pos)
  180. minetest.after(0.2, function (pos)
  181. mesecon.receptor_off(pos, mesecon.rules.flat)
  182. end , pos) -- wait for pending parsings
  183. minetest.add_item(pos, "mesecons_microcontroller:microcontroller0000")
  184. end
  185. local code = meta:get_string("code")
  186. code = yc.code_remove_commentary(code)
  187. code = string.gsub(code, " ", "") --Remove all spaces
  188. code = string.gsub(code, " ", "") --Remove all tabs
  189. if yc.parsecode(code, pos) == nil then
  190. meta:set_string("infotext", "Code not valid!\n"..code)
  191. else
  192. meta:set_string("infotext", "Working Microcontroller\n"..code)
  193. end
  194. end
  195. --Code Parsing
  196. yc.code_remove_commentary = function(code)
  197. local is_string = false
  198. for i = 1, #code do
  199. if code:sub(i, i) == '"' then
  200. is_string = not is_string --toggle is_string
  201. elseif code:sub(i, i) == ":" and not is_string then
  202. return code:sub(1, i-1)
  203. end
  204. end
  205. return code
  206. end
  207. yc.parsecode = function(code, pos)
  208. local meta = minetest.get_meta(pos)
  209. local endi = 1
  210. local Lreal = yc.get_real_portstates(pos)
  211. local Lvirtual = yc.get_virtual_portstates(pos)
  212. if Lvirtual == nil then return nil end
  213. local c
  214. local eeprom = meta:get_string("eeprom")
  215. while true do
  216. local command, params
  217. command, endi = yc.parse_get_command(code, endi)
  218. if command == nil then return nil end
  219. if command == true then break end --end of code
  220. if command == "if" then
  221. local r
  222. r, endi = yc.command_if(code, endi, yc.merge_portstates(Lreal, Lvirtual), eeprom)
  223. if r == nil then return nil end
  224. if r == true then -- nothing
  225. elseif r == false then
  226. local endi_new = yc.skip_to_else (code, endi)
  227. if endi_new == nil then --else > not found
  228. endi = yc.skip_to_endif(code, endi)
  229. else
  230. endi = endi_new
  231. end
  232. if endi == nil then return nil end
  233. end
  234. else
  235. params, endi = yc.parse_get_params(code, endi)
  236. if not params then return nil end
  237. end
  238. if command == "on" then
  239. L = yc.command_on (params, Lvirtual)
  240. elseif command == "off" then
  241. L = yc.command_off(params, Lvirtual)
  242. elseif command == "print" then
  243. local su = yc.command_print(params, eeprom, yc.merge_portstates(Lreal, Lvirtual))
  244. if su ~= true then return nil end
  245. elseif command == "after" then
  246. local su = yc.command_after(params, pos)
  247. if su == nil then return nil end
  248. elseif command == "sbi" then
  249. local new_eeprom
  250. new_eeprom, Lvirtual = yc.command_sbi (params, eeprom, yc.merge_portstates(Lreal, Lvirtual), Lvirtual)
  251. if new_eeprom == nil then return nil
  252. else eeprom = new_eeprom end
  253. elseif command == "if" then --nothing
  254. else
  255. return nil
  256. end
  257. if Lvirtual == nil then return nil end
  258. if eeprom == nil then return nil else
  259. minetest.get_meta(pos):set_string("eeprom", eeprom) end
  260. end
  261. yc.action(pos, Lvirtual)
  262. return true
  263. end
  264. yc.parse_get_command = function(code, starti)
  265. local i = starti
  266. local s
  267. while s ~= "" do
  268. s = string.sub(code, i, i)
  269. if s == "(" then
  270. return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after (
  271. end
  272. if s == ";" and starti == i then
  273. starti = starti + 1
  274. i = starti
  275. elseif s == ">" then
  276. starti = yc.skip_to_endif(code, starti)
  277. if starti == nil then return nil end
  278. i = starti
  279. else
  280. i = i + 1
  281. end
  282. end
  283. if starti == i-1 then
  284. return true, true
  285. end
  286. return nil, nil
  287. end
  288. yc.parse_get_params = function(code, starti)
  289. local i = starti
  290. local s
  291. local params = {}
  292. local is_string = false
  293. while s ~= "" do
  294. s = string.sub(code, i, i)
  295. if code:sub(i, i) == '"' then
  296. is_string = (is_string==false) --toggle is_string
  297. end
  298. if s == ")" and is_string == false then
  299. table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after )
  300. return params, i + 1
  301. end
  302. if s == "," and is_string == false then
  303. table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after )
  304. starti = i + 1
  305. end
  306. i = i + 1
  307. end
  308. return nil, nil
  309. end
  310. yc.parse_get_eeprom_param = function(cond, starti)
  311. local i = starti
  312. local s
  313. local addr
  314. while s ~= "" do
  315. s = string.sub(cond, i, i)
  316. if string.find("0123456789", s) == nil or s == "" then
  317. addr = string.sub(cond, starti, i-1) -- i: last number i+1 after last number
  318. return addr, i
  319. end
  320. if s == "," then return nil, nil end
  321. i = i + 1
  322. end
  323. return nil, nil
  324. end
  325. yc.skip_to_endif = function(code, starti)
  326. local i = starti
  327. local s = false
  328. local open_ifs = 1
  329. while s ~= nil and s~= "" do
  330. s = code:sub(i, i)
  331. if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript
  332. open_ifs = open_ifs + 1
  333. end
  334. if s == ";" then
  335. open_ifs = open_ifs - 1
  336. end
  337. if open_ifs == 0 then
  338. return i + 1
  339. end
  340. i = i + 1
  341. end
  342. return nil
  343. end
  344. yc.skip_to_else = function(code, starti)
  345. local i = starti
  346. local s = false
  347. local open_ifs = 1
  348. while s ~= nil and s~= "" do
  349. s = code:sub(i, i)
  350. if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript
  351. open_ifs = open_ifs + 1
  352. end
  353. if s == ";" then
  354. open_ifs = open_ifs - 1
  355. end
  356. if open_ifs == 1 and s == ">" then
  357. return i + 1
  358. end
  359. i = i + 1
  360. end
  361. return nil
  362. end
  363. --Commands
  364. yc.command_on = function(params, L)
  365. local rules = {}
  366. for i, port in ipairs(params) do
  367. L = yc.set_portstate (port, true, L)
  368. end
  369. return L
  370. end
  371. yc.command_off = function(params, L)
  372. local rules = {}
  373. for i, port in ipairs(params) do
  374. L = yc.set_portstate (port, false, L)
  375. end
  376. return L
  377. end
  378. yc.command_print = function(params, eeprom, L)
  379. local s = ""
  380. for i, param in ipairs(params) do
  381. if param:sub(1,1) == '"' and param:sub(#param, #param) == '"' then
  382. s = s..param:sub(2, #param-1)
  383. else
  384. r = yc.command_parsecondition(param, L, eeprom)
  385. if r == "1" or r == "0" then
  386. s = s..r
  387. else return nil end
  388. end
  389. end
  390. print(s) --don't remove
  391. return true
  392. end
  393. yc.command_sbi = function(params, eeprom, L, Lv)
  394. if params[1]==nil or params[2]==nil or params[3] ~=nil then return nil end
  395. local status = yc.command_parsecondition(params[2], L, eeprom)
  396. if status == nil then return nil, nil end
  397. if string.find("ABCD", params[1])~=nil and #params[1]==1 then --is a port
  398. if status == "1" then
  399. Lv = yc.set_portstate (params[1], true, Lv)
  400. else
  401. Lv = yc.set_portstate (params[1], false, Lv)
  402. end
  403. return eeprom, Lv;
  404. end
  405. --is an eeprom address
  406. local new_eeprom = "";
  407. for i=1, #eeprom do
  408. if tonumber(params[1])==i then
  409. new_eeprom = new_eeprom..status
  410. else
  411. new_eeprom = new_eeprom..eeprom:sub(i, i)
  412. end
  413. end
  414. return new_eeprom, Lv
  415. end
  416. -- after (delay)
  417. yc.command_after = function(params, pos)
  418. if params[1] == nil or params[2] == nil or params[3] ~= nil then return nil end
  419. --get time (maximum time is 200)
  420. local time = tonumber(params[1])
  421. if time == nil or time > 200 then
  422. return nil
  423. end
  424. --get code in quotes "code"
  425. if string.sub(params[2], 1, 1) ~= '"' or string.sub(params[2], #params[2], #params[2]) ~= '"' then return nil end
  426. local code = string.sub(params[2], 2, #params[2] - 1)
  427. local afterid = math.random(10000)
  428. local meta = minetest.get_meta(pos)
  429. meta:set_int("afterid", afterid)
  430. minetest.after(time, yc.command_after_execute, {pos = pos, code = code, afterid = afterid})
  431. return true
  432. end
  433. yc.command_after_execute = function(params)
  434. local meta = minetest.get_meta(params.pos)
  435. if meta:get_int("afterid") == params.afterid then --make sure the node has not been changed
  436. if yc.parsecode(params.code, params.pos) == nil then
  437. meta:set_string("infotext", "Code in after() not valid!")
  438. else
  439. if code ~= nil then
  440. meta:set_string("infotext", "Working Microcontroller\n"..code)
  441. else
  442. meta:set_string("infotext", "Working Microcontroller")
  443. end
  444. end
  445. end
  446. end
  447. --If
  448. yc.command_if = function(code, starti, L, eeprom)
  449. local cond, endi = yc.command_if_getcondition(code, starti)
  450. if cond == nil then return nil end
  451. cond = yc.command_parsecondition(cond, L, eeprom)
  452. local result
  453. if cond == "0" then result = false
  454. elseif cond == "1" then result = true end
  455. if not result then end
  456. return result, endi --endi from local cond, endi = yc.command_if_getcondition(code, starti)
  457. end
  458. --Condition parsing
  459. yc.command_if_getcondition = function(code, starti)
  460. local i = starti
  461. local s
  462. local brackets = 1 --1 Bracket to close
  463. while s ~= "" do
  464. s = string.sub(code, i, i)
  465. if s == ")" then
  466. brackets = brackets - 1
  467. end
  468. if s == "(" then
  469. brackets = brackets + 1
  470. end
  471. if brackets == 0 then
  472. return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after (
  473. end
  474. i = i + 1
  475. end
  476. return nil, nil
  477. end
  478. yc.command_parsecondition = function(cond, L, eeprom)
  479. cond = string.gsub(cond, "A", tonumber(L.a and 1 or 0))
  480. cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0))
  481. cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0))
  482. cond = string.gsub(cond, "D", tonumber(L.d and 1 or 0))
  483. local i = 1
  484. local l = string.len(cond)
  485. while i<=l do
  486. local s = cond:sub(i,i)
  487. if s == "#" then
  488. local addr, endi = yc.parse_get_eeprom_param(cond, i+1)
  489. local buf = yc.eeprom_read(tonumber(addr), eeprom)
  490. if buf == nil then return nil end
  491. local call = cond:sub(i, endi-1)
  492. cond = string.gsub(cond, call, buf)
  493. i = 0
  494. l = string.len(cond)
  495. end
  496. i = i + 1
  497. end
  498. cond = string.gsub(cond, "!0", "1")
  499. cond = string.gsub(cond, "!1", "0")
  500. local i = 2
  501. local l = string.len(cond)
  502. while i<=l do
  503. local s = cond:sub(i,i)
  504. local b = tonumber(cond:sub(i-1, i-1))
  505. local a = tonumber(cond:sub(i+1, i+1))
  506. if cond:sub(i+1, i+1) == nil then break end
  507. if s == "=" then
  508. if a==nil then return nil end
  509. if b==nil then return nil end
  510. if a == b then buf = "1" end
  511. if a ~= b then buf = "0" end
  512. cond = string.gsub(cond, b..s..a, buf)
  513. i = 1
  514. l = string.len(cond)
  515. end
  516. i = i + 1
  517. end
  518. local i = 2
  519. local l = string.len(cond)
  520. while i<=l do
  521. local s = cond:sub(i,i)
  522. local b = tonumber(cond:sub(i-1, i-1))
  523. local a = tonumber(cond:sub(i+1, i+1))
  524. if cond:sub(i+1, i+1) == nil then break end
  525. if s == "&" then
  526. if a==nil then return nil end
  527. if b==nil then return nil end
  528. local buf = ((a==1) and (b==1))
  529. if buf == true then buf = "1" end
  530. if buf == false then buf = "0" end
  531. cond = string.gsub(cond, b..s..a, buf)
  532. i = 1
  533. l = string.len(cond)
  534. end
  535. if s == "|" then
  536. if a==nil then return nil end
  537. if b==nil then return nil end
  538. local buf = ((a == 1) or (b == 1))
  539. if buf == true then buf = "1" end
  540. if buf == false then buf = "0" end
  541. cond = string.gsub(cond, b..s..a, buf)
  542. i = 1
  543. l = string.len(cond)
  544. end
  545. if s == "~" then
  546. if a==nil then return nil end
  547. if b==nil then return nil end
  548. local buf = (((a == 1) or (b == 1)) and not((a==1) and (b==1)))
  549. if buf == true then buf = "1" end
  550. if buf == false then buf = "0" end
  551. cond = string.gsub(cond, b..s..a, buf)
  552. i = 1
  553. l = string.len(cond)
  554. end
  555. i = i + 1
  556. end
  557. return cond
  558. end
  559. --Virtual-Hardware functions
  560. yc.eeprom_read = function(number, eeprom)
  561. if not number then return end
  562. return eeprom:sub(number, number)
  563. end
  564. --Real I/O functions
  565. yc.action = function(pos, L) --L-->Lvirtual
  566. local Lv = yc.get_virtual_portstates(pos)
  567. local name = "mesecons_microcontroller:microcontroller"
  568. ..tonumber(L.d and 1 or 0)
  569. ..tonumber(L.c and 1 or 0)
  570. ..tonumber(L.b and 1 or 0)
  571. ..tonumber(L.a and 1 or 0)
  572. local node = minetest.get_node(pos)
  573. minetest.swap_node(pos, {name = name, param2 = node.param2})
  574. yc.action_setports(pos, L, Lv)
  575. end
  576. yc.action_setports = function(pos, L, Lv)
  577. local name = "mesecons_microcontroller:microcontroller"
  578. local rules
  579. if Lv.a ~= L.a then
  580. rules = microc_rules[name.."0001"]
  581. if L.a == true then mesecon.receptor_on(pos, rules)
  582. else mesecon.receptor_off(pos, rules) end
  583. end
  584. if Lv.b ~= L.b then
  585. rules = microc_rules[name.."0010"]
  586. if L.b == true then mesecon.receptor_on(pos, rules)
  587. else mesecon.receptor_off(pos, rules) end
  588. end
  589. if Lv.c ~= L.c then
  590. rules = microc_rules[name.."0100"]
  591. if L.c == true then mesecon.receptor_on(pos, rules)
  592. else mesecon.receptor_off(pos, rules) end
  593. end
  594. if Lv.d ~= L.d then
  595. rules = microc_rules[name.."1000"]
  596. if L.d == true then mesecon.receptor_on(pos, rules)
  597. else mesecon.receptor_off(pos, rules) end
  598. end
  599. end
  600. yc.set_portstate = function(port, state, L)
  601. if port == "A" then L.a = state
  602. elseif port == "B" then L.b = state
  603. elseif port == "C" then L.c = state
  604. elseif port == "D" then L.d = state
  605. else return nil end
  606. return L
  607. end
  608. yc.update_real_portstates = function(pos, node, rulename, newstate)
  609. local meta = minetest.get_meta(pos)
  610. if rulename == nil then
  611. meta:set_int("real_portstates", 1)
  612. return
  613. end
  614. local n = meta:get_int("real_portstates") - 1
  615. local L = {}
  616. for i = 1, 4 do
  617. L[i] = n%2
  618. n = math.floor(n/2)
  619. end
  620. if rulename.x == nil then
  621. for _, rname in ipairs(rulename) do
  622. local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3]
  623. L[port] = (newstate == "on") and 1 or 0
  624. end
  625. else
  626. local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3]
  627. L[port] = (newstate == "on") and 1 or 0
  628. end
  629. meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
  630. end
  631. yc.get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
  632. local meta = minetest.get_meta(pos)
  633. local L = {}
  634. local n = meta:get_int("real_portstates") - 1
  635. for _, index in ipairs({"a", "b", "c", "d"}) do
  636. L[index] = ((n%2) == 1)
  637. n = math.floor(n/2)
  638. end
  639. return L
  640. end
  641. yc.get_virtual_portstates = function(pos) -- portstates according to the name
  642. local name = minetest.get_node(pos).name
  643. local b, a = string.find(name, ":microcontroller")
  644. if a == nil then return nil end
  645. a = a + 1
  646. local Lvirtual = {a=false, b=false, c=false, d=false}
  647. if name:sub(a , a ) == "1" then Lvirtual.d = true end
  648. if name:sub(a+1, a+1) == "1" then Lvirtual.c = true end
  649. if name:sub(a+2, a+2) == "1" then Lvirtual.b = true end
  650. if name:sub(a+3, a+3) == "1" then Lvirtual.a = true end
  651. return Lvirtual
  652. end
  653. yc.merge_portstates = function(Lreal, Lvirtual)
  654. local L = {a=false, b=false, c=false, d=false}
  655. if Lvirtual.a or Lreal.a then L.a = true end
  656. if Lvirtual.b or Lreal.b then L.b = true end
  657. if Lvirtual.c or Lreal.c then L.c = true end
  658. if Lvirtual.d or Lreal.d then L.d = true end
  659. return L
  660. end