internal.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. -- Internal.lua - The core of mesecons
  2. --
  3. -- For more practical developer resources see mesecons.tk
  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) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on)
  23. -- mesecon:deactivate(pos, node) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off)
  24. -- mesecon:changesignal(pos, node, rulename, newstate) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change)
  25. -- RULES
  26. -- mesecon:add_rules(name, rules) | deprecated? --> Saves rules table by name
  27. -- mesecon:get_rules(name, rules) | deprecated? --> Loads rules table with name
  28. -- CONDUCTORS
  29. -- mesecon:is_conductor(nodename) --> Returns true if nodename is a conductor
  30. -- mesecon:is_conductor_on(nodename) --> Returns true if nodename is a conductor with state = mesecon.state.on
  31. -- mesecon:is_conductor_off(nodename) --> Returns true if nodename is a conductor with state = mesecon.state.off
  32. -- mesecon:get_conductor_on(offstate) --> Returns the onstate nodename of the conductor with the name offstate
  33. -- mesecon:get_conductor_off(onstate) --> Returns the offstate nodename of the conductor with the name onstate
  34. -- mesecon:conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified)
  35. -- HIGH-LEVEL Internals
  36. -- mesecon:is_power_on(pos) --> Returns true if pos emits power in any way
  37. -- mesecon:is_power_off(pos) --> Returns true if pos does not emit power in any way
  38. -- mesecon:turnon(pos, rulename) --> Returns true whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon
  39. -- mesecon:turnoff(pos, rulename) --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff
  40. -- mesecon:connected_to_receptor(pos) --> Returns true if pos is connected to a receptor directly or via conductors; calls itself if pos is a conductor --> recursive
  41. -- mesecon:rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
  42. -- mesecon:rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon:rules_link but also returns true if output and input are swapped
  43. -- mesecon:is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
  44. -- RULES ROTATION helpsers
  45. -- mesecon:rotate_rules_right(rules)
  46. -- mesecon:rotate_rules_left(rules)
  47. -- mesecon:rotate_rules_up(rules)
  48. -- mesecon:rotate_rules_down(rules)
  49. -- These functions return rules that have been rotated in the specific direction
  50. -- General
  51. function mesecon:get_effector(nodename)
  52. if minetest.registered_nodes[nodename]
  53. and minetest.registered_nodes[nodename].mesecons
  54. and minetest.registered_nodes[nodename].mesecons.effector then
  55. return minetest.registered_nodes[nodename].mesecons.effector
  56. end
  57. end
  58. function mesecon:get_receptor(nodename)
  59. if minetest.registered_nodes[nodename]
  60. and minetest.registered_nodes[nodename].mesecons
  61. and minetest.registered_nodes[nodename].mesecons.receptor then
  62. return minetest.registered_nodes[nodename].mesecons.receptor
  63. end
  64. end
  65. function mesecon:get_conductor(nodename)
  66. if minetest.registered_nodes[nodename]
  67. and minetest.registered_nodes[nodename].mesecons
  68. and minetest.registered_nodes[nodename].mesecons.conductor then
  69. return minetest.registered_nodes[nodename].mesecons.conductor
  70. end
  71. end
  72. function mesecon:get_any_outputrules (node)
  73. if mesecon:is_conductor(node.name) then
  74. return mesecon:conductor_get_rules(node)
  75. elseif mesecon:is_receptor(node.name) then
  76. return mesecon:receptor_get_rules(node)
  77. end
  78. return false
  79. end
  80. function mesecon:get_any_inputrules (node)
  81. if mesecon:is_conductor(node.name) then
  82. return mesecon:conductor_get_rules(node)
  83. elseif mesecon:is_effector(node.name) then
  84. return mesecon:effector_get_rules(node)
  85. end
  86. return false
  87. end
  88. -- Receptors
  89. -- Nodes that can power mesecons
  90. function mesecon:is_receptor_on(nodename)
  91. local receptor = mesecon:get_receptor(nodename)
  92. if receptor and receptor.state == mesecon.state.on then
  93. return true
  94. end
  95. return false
  96. end
  97. function mesecon:is_receptor_off(nodename)
  98. local receptor = mesecon:get_receptor(nodename)
  99. if receptor and receptor.state == mesecon.state.off then
  100. return true
  101. end
  102. return false
  103. end
  104. function mesecon:is_receptor(nodename)
  105. local receptor = mesecon:get_receptor(nodename)
  106. if receptor then
  107. return true
  108. end
  109. return false
  110. end
  111. function mesecon:receptor_get_rules(node)
  112. local receptor = mesecon:get_receptor(node.name)
  113. if receptor then
  114. local rules = receptor.rules
  115. if type(rules) == 'function' then
  116. return rules(node)
  117. elseif rules then
  118. return rules
  119. end
  120. end
  121. return mesecon.rules.default
  122. end
  123. -- Effectors
  124. -- Nodes that can be powered by mesecons
  125. function mesecon:is_effector_on(nodename)
  126. local effector = mesecon:get_effector(nodename)
  127. if effector and effector.action_off then
  128. return true
  129. end
  130. return false
  131. end
  132. function mesecon:is_effector_off(nodename)
  133. local effector = mesecon:get_effector(nodename)
  134. if effector and effector.action_on then
  135. return true
  136. end
  137. return false
  138. end
  139. function mesecon:is_effector(nodename)
  140. local effector = mesecon:get_effector(nodename)
  141. if effector then
  142. return true
  143. end
  144. return false
  145. end
  146. function mesecon:effector_get_rules(node)
  147. local effector = mesecon:get_effector(node.name)
  148. if effector then
  149. local rules = effector.rules
  150. if type(rules) == 'function' then
  151. return rules(node)
  152. elseif rules then
  153. return rules
  154. end
  155. end
  156. return mesecon.rules.default
  157. end
  158. --Signals
  159. function mesecon:activate(pos, node, rulename)
  160. local effector = mesecon:get_effector(node.name)
  161. if effector and effector.action_on then
  162. effector.action_on (pos, node, rulename)
  163. end
  164. end
  165. function mesecon:deactivate(pos, node, rulename)
  166. local effector = mesecon:get_effector(node.name)
  167. if effector and effector.action_off then
  168. effector.action_off (pos, node, rulename)
  169. end
  170. end
  171. function mesecon:changesignal(pos, node, rulename, newstate)
  172. local effector = mesecon:get_effector(node.name)
  173. if effector and effector.action_change then
  174. effector.action_change (pos, node, rulename, newstate)
  175. end
  176. end
  177. --Rules
  178. function mesecon:add_rules(name, rules)
  179. mesecon.rules[name] = rules
  180. end
  181. function mesecon:get_rules(name)
  182. return mesecon.rules[name]
  183. end
  184. -- Conductors
  185. function mesecon:is_conductor_on(nodename)
  186. local conductor = mesecon:get_conductor(nodename)
  187. if conductor and conductor.state == mesecon.state.on then
  188. return true
  189. end
  190. return false
  191. end
  192. function mesecon:is_conductor_off(nodename)
  193. local conductor = mesecon:get_conductor(nodename)
  194. if conductor and conductor.state == mesecon.state.off then
  195. return true
  196. end
  197. return false
  198. end
  199. function mesecon:is_conductor(nodename)
  200. local conductor = mesecon:get_conductor(nodename)
  201. if conductor then
  202. return true
  203. end
  204. return false
  205. end
  206. function mesecon:get_conductor_on(offstate)
  207. local conductor = mesecon:get_conductor(offstate)
  208. if conductor then
  209. return conductor.onstate
  210. end
  211. return false
  212. end
  213. function mesecon:get_conductor_off(onstate)
  214. local conductor = mesecon:get_conductor(onstate)
  215. if conductor then
  216. return conductor.offstate
  217. end
  218. return false
  219. end
  220. function mesecon:conductor_get_rules(node)
  221. local conductor = mesecon:get_conductor(node.name)
  222. if conductor then
  223. local rules = conductor.rules
  224. if type(rules) == 'function' then
  225. return rules(node)
  226. elseif rules then
  227. return rules
  228. end
  229. end
  230. return mesecon.rules.default
  231. end
  232. -- some more general high-level stuff
  233. function mesecon:is_power_on(pos)
  234. local node = minetest.env:get_node(pos)
  235. if mesecon:is_conductor_on(node.name) or mesecon:is_receptor_on(node.name) then
  236. return true
  237. end
  238. return false
  239. end
  240. function mesecon:is_power_off(pos)
  241. local node = minetest.env:get_node(pos)
  242. if mesecon:is_conductor_off(node.name) or mesecon:is_receptor_off(node.name) then
  243. return true
  244. end
  245. return false
  246. end
  247. function mesecon:turnon(pos, rulename)
  248. local node = minetest.env:get_node(pos)
  249. if mesecon:is_conductor_off(node.name) then
  250. local rules = mesecon:conductor_get_rules(node)
  251. minetest.env:add_node(pos, {name = mesecon:get_conductor_on(node.name), param2 = node.param2})
  252. for _, rule in ipairs(rules) do
  253. local np = mesecon:addPosRule(pos, rule)
  254. local link, rulename = mesecon:rules_link(pos, np)
  255. if link then
  256. mesecon:turnon(np, rulename)
  257. end
  258. end
  259. elseif mesecon:is_effector(node.name) then
  260. mesecon:changesignal(pos, node, rulename, mesecon.state.on)
  261. if mesecon:is_effector_off(node.name) then
  262. mesecon:activate(pos, node, rulename)
  263. end
  264. end
  265. end
  266. function mesecon:turnoff(pos, rulename)
  267. local node = minetest.env:get_node(pos)
  268. if mesecon:is_conductor_on(node.name) then
  269. local rules = mesecon:conductor_get_rules(node)
  270. minetest.env:add_node(pos, {name = mesecon:get_conductor_off(node.name), param2 = node.param2})
  271. for _, rule in ipairs(rules) do
  272. local np = mesecon:addPosRule(pos, rule)
  273. local link, rulename = mesecon:rules_link(pos, np)
  274. if link then
  275. mesecon:turnoff(np, rulename)
  276. end
  277. end
  278. elseif mesecon:is_effector(node.name) then
  279. mesecon:changesignal(pos, node, rulename, mesecon.state.off)
  280. if mesecon:is_effector_on(node.name)
  281. and not mesecon:is_powered(pos) then
  282. mesecon:deactivate(pos, node, rulename)
  283. end
  284. end
  285. end
  286. function mesecon:connected_to_receptor(pos)
  287. local node = minetest.env:get_node(pos)
  288. -- Check if conductors around are connected
  289. local rules = mesecon:get_any_inputrules(node)
  290. if not rules then return false end
  291. for _, rule in ipairs(rules) do
  292. local np = mesecon:addPosRule(pos, rule)
  293. if mesecon:rules_link(np, pos) then
  294. if mesecon:find_receptor_on(np, {}) then
  295. return true
  296. end
  297. end
  298. end
  299. return false
  300. end
  301. function mesecon:find_receptor_on(pos, checked)
  302. -- find out if node has already been checked (to prevent from endless loop)
  303. for _, cp in ipairs(checked) do
  304. if mesecon:cmpPos(cp, pos) then
  305. return false, checked
  306. end
  307. end
  308. -- add current position to checked
  309. table.insert(checked, {x=pos.x, y=pos.y, z=pos.z})
  310. local node = minetest.env:get_node(pos)
  311. if mesecon:is_receptor_on(node.name) then
  312. return true
  313. end
  314. if mesecon:is_conductor(node.name) then
  315. local rules = mesecon:conductor_get_rules(node)
  316. for _, rule in ipairs(rules) do
  317. local np = mesecon:addPosRule(pos, rule)
  318. if mesecon:rules_link(np, pos) then
  319. if mesecon:find_receptor_on(np, checked) then
  320. return true
  321. end
  322. end
  323. end
  324. end
  325. return false
  326. end
  327. 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
  328. local outputnode = minetest.env:get_node(output)
  329. local inputnode = minetest.env:get_node(input)
  330. local outputrules = dug_outputrules or mesecon:get_any_outputrules (outputnode)
  331. local inputrules = mesecon:get_any_inputrules (inputnode)
  332. if not outputrules or not inputrules then
  333. return
  334. end
  335. for _, outputrule in ipairs(outputrules) do
  336. -- Check if output sends to input
  337. if mesecon:cmpPos(mesecon:addPosRule(output, outputrule), input) then
  338. for _, inputrule in ipairs(inputrules) do
  339. -- Check if input accepts from output
  340. if mesecon:cmpPos(mesecon:addPosRule(input, inputrule), output) then
  341. return true, inputrule.name
  342. end
  343. end
  344. end
  345. end
  346. return false
  347. end
  348. function mesecon:rules_link_anydir(pos1, pos2)
  349. return mesecon:rules_link(pos1, pos2) or mesecon:rules_link(pos2, pos1)
  350. end
  351. function mesecon:is_powered(pos)
  352. local node = minetest.env:get_node(pos)
  353. local rules = mesecon:get_any_inputrules(node)
  354. if not rules then return false end
  355. for _, rule in ipairs(rules) do
  356. local np = mesecon:addPosRule(pos, rule)
  357. local nn = minetest.env:get_node(np)
  358. if (mesecon:is_conductor_on (nn.name) or mesecon:is_receptor_on (nn.name))
  359. and mesecon:rules_link(np, pos) then
  360. return true
  361. end
  362. end
  363. return false
  364. end
  365. --Rules rotation Functions:
  366. function mesecon:rotate_rules_right(rules)
  367. local nr = {}
  368. for i, rule in ipairs(rules) do
  369. table.insert(nr, {
  370. x = -rule.z,
  371. y = rule.y,
  372. z = rule.x})
  373. end
  374. return nr
  375. end
  376. function mesecon:rotate_rules_left(rules)
  377. local nr = {}
  378. for i, rule in ipairs(rules) do
  379. table.insert(nr, {
  380. x = rule.z,
  381. y = rule.y,
  382. z = -rule.x})
  383. end
  384. return nr
  385. end
  386. function mesecon:rotate_rules_down(rules)
  387. local nr = {}
  388. for i, rule in ipairs(rules) do
  389. table.insert(nr, {
  390. x = -rule.y,
  391. y = rule.x,
  392. z = rule.z})
  393. end
  394. return nr
  395. end
  396. function mesecon:rotate_rules_up(rules)
  397. local nr = {}
  398. for i, rule in ipairs(rules) do
  399. table.insert(nr, {
  400. x = rule.y,
  401. y = -rule.x,
  402. z = rule.z})
  403. end
  404. return nr
  405. end