internal.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. -- Internal.lua - The core of mesecons
  2. --
  3. -- For more practical developer resources see http://mesecons.net/developers.php
  4. --
  5. -- Function overview
  6. -- mesecon.get_effector(nodename) --> Returns the mesecons.effector -specifictation in the nodedef by the nodename
  7. -- mesecon.get_receptor(nodename) --> Returns the mesecons.receptor -specifictation in the nodedef by the nodename
  8. -- mesecon.get_conductor(nodename) --> Returns the mesecons.conductor-specifictation in the nodedef by the nodename
  9. -- mesecon.get_any_inputrules (node) --> Returns the rules of a node if it is a conductor or an effector
  10. -- mesecon.get_any_outputrules (node) --> Returns the rules of a node if it is a conductor or a receptor
  11. -- RECEPTORS
  12. -- mesecon.is_receptor(nodename) --> Returns true if nodename is a receptor
  13. -- mesecon.is_receptor_on(nodename --> Returns true if nodename is an receptor with state = mesecon.state.on
  14. -- mesecon.is_receptor_off(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.off
  15. -- mesecon.receptor_get_rules(node) --> Returns the rules of the receptor (mesecon.rules.default if none specified)
  16. -- EFFECTORS
  17. -- mesecon.is_effector(nodename) --> Returns true if nodename is an effector
  18. -- mesecon.is_effector_on(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_off
  19. -- mesecon.is_effector_off(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_on
  20. -- mesecon.effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified)
  21. -- SIGNALS
  22. -- mesecon.activate(pos, node, depth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher depths are executed later
  23. -- mesecon.deactivate(pos, node, depth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), higher depths are executed later
  24. -- mesecon.changesignal(pos, node, rulename, newstate, depth) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), higher depths are executed later
  25. -- CONDUCTORS
  26. -- mesecon.is_conductor(nodename) --> Returns true if nodename is a conductor
  27. -- mesecon.is_conductor_on(node --> Returns true if node is a conductor with state = mesecon.state.on
  28. -- mesecon.is_conductor_off(node) --> Returns true if node is a conductor with state = mesecon.state.off
  29. -- mesecon.get_conductor_on(node_off) --> Returns the onstate nodename of the conductor
  30. -- mesecon.get_conductor_off(node_on) --> Returns the offstate nodename of the conductor
  31. -- mesecon.conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified)
  32. -- HIGH-LEVEL Internals
  33. -- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way
  34. -- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way
  35. -- mesecon.turnon(pos, link) --> link is the input rule that caused calling turnon, turns on every connected node, iterative
  36. -- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative
  37. -- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative
  38. -- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
  39. -- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped
  40. -- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
  41. -- RULES ROTATION helpers
  42. -- mesecon.rotate_rules_right(rules)
  43. -- mesecon.rotate_rules_left(rules)
  44. -- mesecon.rotate_rules_up(rules)
  45. -- mesecon.rotate_rules_down(rules)
  46. -- These functions return rules that have been rotated in the specific direction
  47. -- General
  48. function mesecon.get_effector(nodename)
  49. if minetest.registered_nodes[nodename]
  50. and minetest.registered_nodes[nodename].mesecons
  51. and minetest.registered_nodes[nodename].mesecons.effector then
  52. return minetest.registered_nodes[nodename].mesecons.effector
  53. end
  54. end
  55. function mesecon.get_receptor(nodename)
  56. if minetest.registered_nodes[nodename]
  57. and minetest.registered_nodes[nodename].mesecons
  58. and minetest.registered_nodes[nodename].mesecons.receptor then
  59. return minetest.registered_nodes[nodename].mesecons.receptor
  60. end
  61. end
  62. function mesecon.get_conductor(nodename)
  63. if minetest.registered_nodes[nodename]
  64. and minetest.registered_nodes[nodename].mesecons
  65. and minetest.registered_nodes[nodename].mesecons.conductor then
  66. return minetest.registered_nodes[nodename].mesecons.conductor
  67. end
  68. end
  69. function mesecon.get_any_outputrules (node)
  70. if mesecon.is_conductor(node.name) then
  71. return mesecon.conductor_get_rules(node)
  72. elseif mesecon.is_receptor(node.name) then
  73. return mesecon.receptor_get_rules(node)
  74. end
  75. end
  76. function mesecon.get_any_inputrules (node)
  77. if mesecon.is_conductor(node.name) then
  78. return mesecon.conductor_get_rules(node)
  79. elseif mesecon.is_effector(node.name) then
  80. return mesecon.effector_get_rules(node)
  81. end
  82. end
  83. function mesecon.get_any_rules (node)
  84. return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
  85. mesecon.get_any_outputrules(node) or {})
  86. end
  87. -- Receptors
  88. -- Nodes that can power mesecons
  89. function mesecon.is_receptor_on(nodename)
  90. local receptor = mesecon.get_receptor(nodename)
  91. if receptor and receptor.state == mesecon.state.on then
  92. return true
  93. end
  94. return false
  95. end
  96. function mesecon.is_receptor_off(nodename)
  97. local receptor = mesecon.get_receptor(nodename)
  98. if receptor and receptor.state == mesecon.state.off then
  99. return true
  100. end
  101. return false
  102. end
  103. function mesecon.is_receptor(nodename)
  104. local receptor = mesecon.get_receptor(nodename)
  105. if receptor then
  106. return true
  107. end
  108. return false
  109. end
  110. function mesecon.receptor_get_rules(node)
  111. local receptor = mesecon.get_receptor(node.name)
  112. if receptor then
  113. local rules = receptor.rules
  114. if type(rules) == 'function' then
  115. return rules(node)
  116. elseif rules then
  117. return rules
  118. end
  119. end
  120. return mesecon.rules.default
  121. end
  122. -- Effectors
  123. -- Nodes that can be powered by mesecons
  124. function mesecon.is_effector_on(nodename)
  125. local effector = mesecon.get_effector(nodename)
  126. if effector and effector.action_off then
  127. return true
  128. end
  129. return false
  130. end
  131. function mesecon.is_effector_off(nodename)
  132. local effector = mesecon.get_effector(nodename)
  133. if effector and effector.action_on then
  134. return true
  135. end
  136. return false
  137. end
  138. function mesecon.is_effector(nodename)
  139. local effector = mesecon.get_effector(nodename)
  140. if effector then
  141. return true
  142. end
  143. return false
  144. end
  145. function mesecon.effector_get_rules(node)
  146. local effector = mesecon.get_effector(node.name)
  147. if effector then
  148. local rules = effector.rules
  149. if type(rules) == 'function' then
  150. return rules(node)
  151. elseif rules then
  152. return rules
  153. end
  154. end
  155. return mesecon.rules.default
  156. end
  157. -- #######################
  158. -- # Signals (effectors) #
  159. -- #######################
  160. -- Activation:
  161. mesecon.queue:add_function("activate", function (pos, rulename)
  162. local node = minetest.get_node(pos)
  163. local effector = mesecon.get_effector(node.name)
  164. if effector and effector.action_on then
  165. effector.action_on(pos, node, rulename)
  166. end
  167. end)
  168. function mesecon.activate(pos, node, rulename, depth)
  169. if rulename == nil then
  170. for _,rule in ipairs(mesecon.effector_get_rules(node)) do
  171. mesecon.activate(pos, node, rule, depth + 1)
  172. end
  173. return
  174. end
  175. mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth)
  176. end
  177. -- Deactivation
  178. mesecon.queue:add_function("deactivate", function (pos, rulename)
  179. local node = minetest.get_node(pos)
  180. local effector = mesecon.get_effector(node.name)
  181. if effector and effector.action_off then
  182. effector.action_off(pos, node, rulename)
  183. end
  184. end)
  185. function mesecon.deactivate(pos, node, rulename, depth)
  186. if rulename == nil then
  187. for _,rule in ipairs(mesecon.effector_get_rules(node)) do
  188. mesecon.deactivate(pos, node, rule, depth + 1)
  189. end
  190. return
  191. end
  192. mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth)
  193. end
  194. -- Change
  195. mesecon.queue:add_function("change", function (pos, rulename, changetype)
  196. local node = minetest.get_node(pos)
  197. local effector = mesecon.get_effector(node.name)
  198. if effector and effector.action_change then
  199. effector.action_change(pos, node, rulename, changetype)
  200. end
  201. end)
  202. function mesecon.changesignal(pos, node, rulename, newstate, depth)
  203. if rulename == nil then
  204. for _,rule in ipairs(mesecon.effector_get_rules(node)) do
  205. mesecon.changesignal(pos, node, rule, newstate, depth + 1)
  206. end
  207. return
  208. end
  209. -- Include "change" in overwritecheck so that it cannot be overwritten
  210. -- by "active" / "deactivate" that will be called upon the node at the same time.
  211. local overwritecheck = {"change", rulename}
  212. mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, overwritecheck, 1 / depth)
  213. end
  214. -- Conductors
  215. function mesecon.is_conductor_on(node, rulename)
  216. local conductor = mesecon.get_conductor(node.name)
  217. if conductor then
  218. if conductor.state then
  219. return conductor.state == mesecon.state.on
  220. end
  221. if conductor.states then
  222. if not rulename then
  223. return mesecon.getstate(node.name, conductor.states) ~= 1
  224. end
  225. local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node))
  226. local binstate = mesecon.getbinstate(node.name, conductor.states)
  227. return mesecon.get_bit(binstate, bit)
  228. end
  229. end
  230. return false
  231. end
  232. function mesecon.is_conductor_off(node, rulename)
  233. local conductor = mesecon.get_conductor(node.name)
  234. if conductor then
  235. if conductor.state then
  236. return conductor.state == mesecon.state.off
  237. end
  238. if conductor.states then
  239. if not rulename then
  240. return mesecon.getstate(node.name, conductor.states) == 1
  241. end
  242. local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node))
  243. local binstate = mesecon.getbinstate(node.name, conductor.states)
  244. return not mesecon.get_bit(binstate, bit)
  245. end
  246. end
  247. return false
  248. end
  249. function mesecon.is_conductor(nodename)
  250. local conductor = mesecon.get_conductor(nodename)
  251. if conductor then
  252. return true
  253. end
  254. return false
  255. end
  256. function mesecon.get_conductor_on(node_off, rulename)
  257. local conductor = mesecon.get_conductor(node_off.name)
  258. if conductor then
  259. if conductor.onstate then
  260. return conductor.onstate
  261. end
  262. if conductor.states then
  263. local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_off))
  264. local binstate = mesecon.getbinstate(node_off.name, conductor.states)
  265. binstate = mesecon.set_bit(binstate, bit, "1")
  266. return conductor.states[tonumber(binstate,2)+1]
  267. end
  268. end
  269. return offstate
  270. end
  271. function mesecon.get_conductor_off(node_on, rulename)
  272. local conductor = mesecon.get_conductor(node_on.name)
  273. if conductor then
  274. if conductor.offstate then
  275. return conductor.offstate
  276. end
  277. if conductor.states then
  278. local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_on))
  279. local binstate = mesecon.getbinstate(node_on.name, conductor.states)
  280. binstate = mesecon.set_bit(binstate, bit, "0")
  281. return conductor.states[tonumber(binstate,2)+1]
  282. end
  283. end
  284. return onstate
  285. end
  286. function mesecon.conductor_get_rules(node)
  287. local conductor = mesecon.get_conductor(node.name)
  288. if conductor then
  289. local rules = conductor.rules
  290. if type(rules) == 'function' then
  291. return rules(node)
  292. elseif rules then
  293. return rules
  294. end
  295. end
  296. return mesecon.rules.default
  297. end
  298. -- some more general high-level stuff
  299. function mesecon.is_power_on(pos, rulename)
  300. local node = minetest.get_node(pos)
  301. if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then
  302. return true
  303. end
  304. return false
  305. end
  306. function mesecon.is_power_off(pos, rulename)
  307. local node = minetest.get_node(pos)
  308. if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then
  309. return true
  310. end
  311. return false
  312. end
  313. function mesecon.turnon(pos, link)
  314. local frontiers = {{pos = pos, link = link}}
  315. local depth = 1
  316. while frontiers[depth] do
  317. local f = frontiers[depth]
  318. local node = minetest.get_node_or_nil(f.pos)
  319. -- area not loaded, postpone action
  320. if not node then
  321. mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
  322. elseif mesecon.is_conductor_off(node, f.link) then
  323. local rules = mesecon.conductor_get_rules(node)
  324. minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link),
  325. param2 = node.param2})
  326. -- call turnon on neighbors: normal rules
  327. for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
  328. local np = mesecon.addPosRule(f.pos, r)
  329. -- area not loaded, postpone action
  330. if not minetest.get_node_or_nil(np) then
  331. mesecon.queue:add_action(np, "turnon", {rulename},
  332. nil, true)
  333. else
  334. local links = mesecon.rules_link_rule_all(f.pos, r)
  335. for _, l in ipairs(links) do
  336. table.insert(frontiers, {pos = np, link = l})
  337. end
  338. end
  339. end
  340. elseif mesecon.is_effector(node.name) then
  341. mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth)
  342. if mesecon.is_effector_off(node.name) then
  343. mesecon.activate(f.pos, node, f.link, depth)
  344. end
  345. end
  346. depth = depth + 1
  347. end
  348. end
  349. mesecon.queue:add_function("turnon", function (pos, rulename, recdepth)
  350. mesecon.turnon(pos, rulename, recdepth)
  351. end)
  352. function mesecon.turnoff(pos, link)
  353. local frontiers = {{pos = pos, link = link}}
  354. local depth = 1
  355. while frontiers[depth] do
  356. local f = frontiers[depth]
  357. local node = minetest.get_node_or_nil(f.pos)
  358. -- area not loaded, postpone action
  359. if not node then
  360. mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true)
  361. elseif mesecon.is_conductor_on(node, f.link) then
  362. local rules = mesecon.conductor_get_rules(node)
  363. minetest.swap_node(f.pos, {name = mesecon.get_conductor_off(node, f.link),
  364. param2 = node.param2})
  365. -- call turnoff on neighbors: normal rules
  366. for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
  367. local np = mesecon.addPosRule(f.pos, r)
  368. -- area not loaded, postpone action
  369. if not minetest.get_node_or_nil(np) then
  370. mesecon.queue:add_action(np, "turnoff", {rulename},
  371. nil, true)
  372. else
  373. local links = mesecon.rules_link_rule_all(f.pos, r)
  374. for _, l in ipairs(links) do
  375. table.insert(frontiers, {pos = np, link = l})
  376. end
  377. end
  378. end
  379. elseif mesecon.is_effector(node.name) then
  380. mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth)
  381. if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then
  382. mesecon.deactivate(f.pos, node, f.link, depth)
  383. end
  384. end
  385. depth = depth + 1
  386. end
  387. end
  388. mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth)
  389. mesecon.turnoff(pos, rulename, recdepth)
  390. end)
  391. function mesecon.connected_to_receptor(pos, link)
  392. local node = minetest.get_node(pos)
  393. -- Check if conductors around are connected
  394. local rules = mesecon.get_any_inputrules(node)
  395. if not rules then return false end
  396. for _, rule in ipairs(mesecon.rule2meta(link, rules)) do
  397. local links = mesecon.rules_link_rule_all_inverted(pos, rule)
  398. for _, l in ipairs(links) do
  399. local np = mesecon.addPosRule(pos, l)
  400. if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
  401. return true
  402. end
  403. end
  404. end
  405. return false
  406. end
  407. function mesecon.find_receptor_on(pos, link)
  408. local frontiers = {{pos = pos, link = link}}
  409. local checked = {}
  410. -- List of positions that have been searched for onstate receptors
  411. local depth = 1
  412. while frontiers[depth] do
  413. local f = frontiers[depth]
  414. local node = minetest.get_node_or_nil(f.pos)
  415. if not node then return false end
  416. if mesecon.is_receptor_on(node.name) then return true end
  417. if mesecon.is_conductor_on(node, f.link) then
  418. local rules = mesecon.conductor_get_rules(node)
  419. -- call turnoff on neighbors: normal rules
  420. for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
  421. local np = mesecon.addPosRule(f.pos, r)
  422. local links = mesecon.rules_link_rule_all_inverted(f.pos, r)
  423. for _, l in ipairs(links) do
  424. local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z
  425. if not checked[checkedstring] then
  426. table.insert(frontiers, {pos = np, link = l})
  427. checked[checkedstring] = true
  428. end
  429. end
  430. end
  431. end
  432. depth = depth + 1
  433. end
  434. end
  435. function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule
  436. local outputnode = minetest.get_node(output)
  437. local inputnode = minetest.get_node(input)
  438. local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
  439. local inputrules = mesecon.get_any_inputrules (inputnode)
  440. if not outputrules or not inputrules then
  441. return
  442. end
  443. for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
  444. -- Check if output sends to input
  445. if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
  446. for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
  447. -- Check if input accepts from output
  448. if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
  449. return true, inputrule
  450. end
  451. end
  452. end
  453. end
  454. return false
  455. end
  456. function mesecon.rules_link_rule_all(output, rule)
  457. local input = mesecon.addPosRule(output, rule)
  458. local inputnode = minetest.get_node(input)
  459. local inputrules = mesecon.get_any_inputrules (inputnode)
  460. if not inputrules then
  461. return {}
  462. end
  463. local rules = {}
  464. for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
  465. -- Check if input accepts from output
  466. if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
  467. table.insert(rules, inputrule)
  468. end
  469. end
  470. return rules
  471. end
  472. function mesecon.rules_link_rule_all_inverted(input, rule)
  473. --local irule = mesecon.invertRule(rule)
  474. local output = mesecon.addPosRule(input, rule)
  475. local outputnode = minetest.get_node(output)
  476. local outputrules = mesecon.get_any_outputrules (outputnode)
  477. if not outputrules then
  478. return {}
  479. end
  480. local rules = {}
  481. for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
  482. if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
  483. table.insert(rules, mesecon.invertRule(outputrule))
  484. end
  485. end
  486. return rules
  487. end
  488. function mesecon.rules_link_anydir(pos1, pos2)
  489. return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1)
  490. end
  491. function mesecon.is_powered(pos, rule)
  492. local node = minetest.get_node(pos)
  493. local rules = mesecon.get_any_inputrules(node)
  494. if not rules then return false end
  495. -- List of nodes that send out power to pos
  496. local sourcepos = {}
  497. if not rule then
  498. for _, rule in ipairs(mesecon.flattenrules(rules)) do
  499. local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
  500. for _, rname in ipairs(rulenames) do
  501. local np = mesecon.addPosRule(pos, rname)
  502. local nn = minetest.get_node(np)
  503. if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
  504. or mesecon.is_receptor_on (nn.name)) then
  505. table.insert(sourcepos, np)
  506. end
  507. end
  508. end
  509. else
  510. local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
  511. for _, rname in ipairs(rulenames) do
  512. local np = mesecon.addPosRule(pos, rname)
  513. local nn = minetest.get_node(np)
  514. if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
  515. or mesecon.is_receptor_on (nn.name)) then
  516. table.insert(sourcepos, np)
  517. end
  518. end
  519. end
  520. -- Return FALSE if not powered, return list of sources if is powered
  521. if (#sourcepos == 0) then return false
  522. else return sourcepos end
  523. end
  524. --Rules rotation Functions:
  525. function mesecon.rotate_rules_right(rules)
  526. local nr = {}
  527. for i, rule in ipairs(rules) do
  528. table.insert(nr, {
  529. x = -rule.z,
  530. y = rule.y,
  531. z = rule.x,
  532. name = rule.name})
  533. end
  534. return nr
  535. end
  536. function mesecon.rotate_rules_left(rules)
  537. local nr = {}
  538. for i, rule in ipairs(rules) do
  539. table.insert(nr, {
  540. x = rule.z,
  541. y = rule.y,
  542. z = -rule.x,
  543. name = rule.name})
  544. end
  545. return nr
  546. end
  547. function mesecon.rotate_rules_down(rules)
  548. local nr = {}
  549. for i, rule in ipairs(rules) do
  550. table.insert(nr, {
  551. x = -rule.y,
  552. y = rule.x,
  553. z = rule.z,
  554. name = rule.name})
  555. end
  556. return nr
  557. end
  558. function mesecon.rotate_rules_up(rules)
  559. local nr = {}
  560. for i, rule in ipairs(rules) do
  561. table.insert(nr, {
  562. x = rule.y,
  563. y = -rule.x,
  564. z = rule.z,
  565. name = rule.name})
  566. end
  567. return nr
  568. end