init.lua 19 KB

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