2015-06-29 19:55:56 +02:00
-- Internal.lua - The core of mesecons
--
2017-07-31 00:12:21 +02:00
-- For more practical developer resources see http://mesecons.net/developers.php
2015-06-29 19:55:56 +02:00
--
-- Function overview
2017-07-31 00:12:21 +02:00
-- mesecon.get_effector(nodename) --> Returns the mesecons.effector -specifictation in the nodedef by the nodename
-- mesecon.get_receptor(nodename) --> Returns the mesecons.receptor -specifictation in the nodedef by the nodename
-- mesecon.get_conductor(nodename) --> Returns the mesecons.conductor-specifictation in the nodedef by the nodename
-- mesecon.get_any_inputrules (node) --> Returns the rules of a node if it is a conductor or an effector
-- mesecon.get_any_outputrules (node) --> Returns the rules of a node if it is a conductor or a receptor
2015-06-29 19:55:56 +02:00
-- RECEPTORS
2017-07-31 00:12:21 +02:00
-- mesecon.is_receptor(nodename) --> Returns true if nodename is a receptor
-- mesecon.is_receptor_on(nodename --> Returns true if nodename is an receptor with state = mesecon.state.on
-- mesecon.is_receptor_off(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.off
-- mesecon.receptor_get_rules(node) --> Returns the rules of the receptor (mesecon.rules.default if none specified)
2015-06-29 19:55:56 +02:00
-- EFFECTORS
2017-07-31 00:12:21 +02:00
-- mesecon.is_effector(nodename) --> Returns true if nodename is an effector
-- mesecon.is_effector_on(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_off
-- mesecon.is_effector_off(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_on
-- mesecon.effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified)
2015-06-29 19:55:56 +02:00
-- SIGNALS
2017-07-31 00:12:21 +02:00
-- mesecon.activate(pos, node, depth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher depths are executed later
-- mesecon.deactivate(pos, node, depth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), higher depths are executed later
-- 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
2015-06-29 19:55:56 +02:00
-- CONDUCTORS
2017-07-31 00:12:21 +02:00
-- mesecon.is_conductor(nodename) --> Returns true if nodename is a conductor
-- mesecon.is_conductor_on(node --> Returns true if node is a conductor with state = mesecon.state.on
-- mesecon.is_conductor_off(node) --> Returns true if node is a conductor with state = mesecon.state.off
-- mesecon.get_conductor_on(node_off) --> Returns the onstate nodename of the conductor
-- mesecon.get_conductor_off(node_on) --> Returns the offstate nodename of the conductor
-- mesecon.conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified)
2015-06-29 19:55:56 +02:00
-- HIGH-LEVEL Internals
2017-07-31 00:12:21 +02:00
-- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way
-- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way
2018-01-17 20:23:43 +01:00
-- mesecon.is_powered(pos) --> Returns bool, spread. bool is true if pos is powered by a receptor, a conductor or an opaque block.
-- spread is true if it is powered AND also transmits its power one block further.
2017-07-31 00:12:21 +02:00
-- RULES ROTATION helpers
-- mesecon.rotate_rules_right(rules)
-- mesecon.rotate_rules_left(rules)
-- mesecon.rotate_rules_up(rules)
-- mesecon.rotate_rules_down(rules)
2015-06-29 19:55:56 +02:00
-- These functions return rules that have been rotated in the specific direction
2021-04-09 00:08:03 +02:00
local equals = vector.equals
local get_node_force = mesecon.get_node_force
local receptor_get_rules = mesecon.receptor_get_rules
local invertRule = mesecon.invertRule
local copy , insert = table.copy , table.insert
local registered_nodes = minetest.registered_nodes
2015-06-29 19:55:56 +02:00
-- General
2017-07-31 00:12:21 +02:00
function mesecon . get_effector ( nodename )
2021-04-09 00:08:03 +02:00
if registered_nodes [ nodename ]
and registered_nodes [ nodename ] . mesecons
and registered_nodes [ nodename ] . mesecons.effector then
return registered_nodes [ nodename ] . mesecons.effector
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
function mesecon . get_receptor ( nodename )
2021-04-09 00:08:03 +02:00
if registered_nodes [ nodename ]
and registered_nodes [ nodename ] . mesecons
and registered_nodes [ nodename ] . mesecons.receptor then
return registered_nodes [ nodename ] . mesecons.receptor
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
function mesecon . get_conductor ( nodename )
2021-04-09 00:08:03 +02:00
if registered_nodes [ nodename ]
and registered_nodes [ nodename ] . mesecons
and registered_nodes [ nodename ] . mesecons.conductor then
return registered_nodes [ nodename ] . mesecons.conductor
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
function mesecon . get_any_outputrules ( node )
if not node then return nil end
if mesecon.is_conductor ( node.name ) then
return mesecon.conductor_get_rules ( node )
elseif mesecon.is_receptor ( node.name ) then
return mesecon.receptor_get_rules ( node )
2018-01-17 02:44:00 +01:00
elseif minetest.get_item_group ( node.name , " opaque " ) == 1 then
return mesecon.rules . alldirs
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
function mesecon . get_any_inputrules ( node )
if not node then return nil end
if mesecon.is_conductor ( node.name ) then
return mesecon.conductor_get_rules ( node )
elseif mesecon.is_effector ( node.name ) then
return mesecon.effector_get_rules ( node )
2018-01-17 02:44:00 +01:00
elseif minetest.get_item_group ( node.name , " opaque " ) == 1 then
return mesecon.rules . alldirs
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
end
function mesecon . get_any_rules ( node )
return mesecon.mergetable ( mesecon.get_any_inputrules ( node ) or { } ,
mesecon.get_any_outputrules ( node ) or { } )
2015-06-29 19:55:56 +02:00
end
-- Receptors
-- Nodes that can power mesecons
2021-04-09 00:08:03 +02:00
local function is_receptor_on ( nodename )
2017-07-31 00:12:21 +02:00
local receptor = mesecon.get_receptor ( nodename )
2015-06-29 19:55:56 +02:00
if receptor and receptor.state == mesecon.state . on then
return true
end
return false
end
2021-04-09 00:08:03 +02:00
mesecon.is_receptor_on = is_receptor_on
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
function mesecon . is_receptor_off ( nodename )
local receptor = mesecon.get_receptor ( nodename )
2015-06-29 19:55:56 +02:00
if receptor and receptor.state == mesecon.state . off then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_receptor ( nodename )
local receptor = mesecon.get_receptor ( nodename )
2015-06-29 19:55:56 +02:00
if receptor then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . receptor_get_rules ( node )
local receptor = mesecon.get_receptor ( node.name )
2015-06-29 19:55:56 +02:00
if receptor then
local rules = receptor.rules
if type ( rules ) == ' function ' then
return rules ( node )
elseif rules then
return rules
end
end
return mesecon.rules . default
end
-- Effectors
-- Nodes that can be powered by mesecons
2017-07-31 00:12:21 +02:00
function mesecon . is_effector_on ( nodename )
local effector = mesecon.get_effector ( nodename )
2015-06-29 19:55:56 +02:00
if effector and effector.action_off then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_effector_off ( nodename )
local effector = mesecon.get_effector ( nodename )
2015-06-29 19:55:56 +02:00
if effector and effector.action_on then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_effector ( nodename )
local effector = mesecon.get_effector ( nodename )
2015-06-29 19:55:56 +02:00
if effector then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . effector_get_rules ( node )
local effector = mesecon.get_effector ( node.name )
2015-06-29 19:55:56 +02:00
if effector then
local rules = effector.rules
if type ( rules ) == ' function ' then
return rules ( node )
elseif rules then
return rules
end
end
return mesecon.rules . default
end
2017-07-31 00:12:21 +02:00
-- #######################
-- # Signals (effectors) #
-- #######################
-- Activation:
mesecon.queue : add_function ( " activate " , function ( pos , rulename )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
2017-07-31 00:12:21 +02:00
if not node then return end
local effector = mesecon.get_effector ( node.name )
2015-06-29 19:55:56 +02:00
if effector and effector.action_on then
2017-07-31 00:12:21 +02:00
effector.action_on ( pos , node , rulename )
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
end )
function mesecon . activate ( pos , node , rulename , depth )
if rulename == nil then
2021-04-09 00:08:03 +02:00
for _ , rule in pairs ( mesecon.effector_get_rules ( node ) ) do
2017-07-31 00:12:21 +02:00
mesecon.activate ( pos , node , rule , depth + 1 )
end
return
end
mesecon.queue : add_action ( pos , " activate " , { rulename } , nil , rulename , 1 / depth )
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
-- Deactivation
mesecon.queue : add_function ( " deactivate " , function ( pos , rulename )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
2017-07-31 00:12:21 +02:00
if not node then return end
local effector = mesecon.get_effector ( node.name )
2015-06-29 19:55:56 +02:00
if effector and effector.action_off then
2017-07-31 00:12:21 +02:00
effector.action_off ( pos , node , rulename )
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
end )
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
function mesecon . deactivate ( pos , node , rulename , depth )
if rulename == nil then
2021-04-09 00:08:03 +02:00
for _ , rule in pairs ( mesecon.effector_get_rules ( node ) ) do
2017-07-31 00:12:21 +02:00
mesecon.deactivate ( pos , node , rule , depth + 1 )
end
return
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
mesecon.queue : add_action ( pos , " deactivate " , { rulename } , nil , rulename , 1 / depth )
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
-- Change
mesecon.queue : add_function ( " change " , function ( pos , rulename , changetype )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
2017-07-31 00:12:21 +02:00
if not node then return end
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
local effector = mesecon.get_effector ( node.name )
if effector and effector.action_change then
effector.action_change ( pos , node , rulename , changetype )
end
end )
function mesecon . changesignal ( pos , node , rulename , newstate , depth )
if rulename == nil then
2021-04-09 00:08:03 +02:00
for _ , rule in pairs ( mesecon.effector_get_rules ( node ) ) do
2017-07-31 00:12:21 +02:00
mesecon.changesignal ( pos , node , rule , newstate , depth + 1 )
end
return
end
-- Include "change" in overwritecheck so that it cannot be overwritten
-- by "active" / "deactivate" that will be called upon the node at the same time.
local overwritecheck = { " change " , rulename }
mesecon.queue : add_action ( pos , " change " , { rulename , newstate } , nil , overwritecheck , 1 / depth )
2015-06-29 19:55:56 +02:00
end
-- Conductors
2017-07-31 00:12:21 +02:00
function mesecon . is_conductor_on ( node , rulename )
if not node then return false end
local conductor = mesecon.get_conductor ( node.name )
if conductor then
if conductor.state then
return conductor.state == mesecon.state . on
end
if conductor.states then
if not rulename then
return mesecon.getstate ( node.name , conductor.states ) ~= 1
end
local bit = mesecon.rule2bit ( rulename , mesecon.conductor_get_rules ( node ) )
local binstate = mesecon.getbinstate ( node.name , conductor.states )
return mesecon.get_bit ( binstate , bit )
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
2015-06-29 19:55:56 +02:00
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_conductor_off ( node , rulename )
if not node then return false end
local conductor = mesecon.get_conductor ( node.name )
if conductor then
if conductor.state then
return conductor.state == mesecon.state . off
end
if conductor.states then
if not rulename then
return mesecon.getstate ( node.name , conductor.states ) == 1
end
local bit = mesecon.rule2bit ( rulename , mesecon.conductor_get_rules ( node ) )
local binstate = mesecon.getbinstate ( node.name , conductor.states )
return not mesecon.get_bit ( binstate , bit )
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
2015-06-29 19:55:56 +02:00
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_conductor ( nodename )
local conductor = mesecon.get_conductor ( nodename )
2015-06-29 19:55:56 +02:00
if conductor then
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . get_conductor_on ( node_off , rulename )
local conductor = mesecon.get_conductor ( node_off.name )
2015-06-29 19:55:56 +02:00
if conductor then
2017-07-31 00:12:21 +02:00
if conductor.onstate then
return conductor.onstate
end
if conductor.states then
local bit = mesecon.rule2bit ( rulename , mesecon.conductor_get_rules ( node_off ) )
local binstate = mesecon.getbinstate ( node_off.name , conductor.states )
binstate = mesecon.set_bit ( binstate , bit , " 1 " )
return conductor.states [ tonumber ( binstate , 2 ) + 1 ]
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
return offstate
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
function mesecon . get_conductor_off ( node_on , rulename )
local conductor = mesecon.get_conductor ( node_on.name )
2015-06-29 19:55:56 +02:00
if conductor then
2017-07-31 00:12:21 +02:00
if conductor.offstate then
return conductor.offstate
end
if conductor.states then
local bit = mesecon.rule2bit ( rulename , mesecon.conductor_get_rules ( node_on ) )
local binstate = mesecon.getbinstate ( node_on.name , conductor.states )
binstate = mesecon.set_bit ( binstate , bit , " 0 " )
return conductor.states [ tonumber ( binstate , 2 ) + 1 ]
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
return onstate
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
function mesecon . conductor_get_rules ( node )
local conductor = mesecon.get_conductor ( node.name )
2015-06-29 19:55:56 +02:00
if conductor then
local rules = conductor.rules
if type ( rules ) == ' function ' then
return rules ( node )
elseif rules then
return rules
end
end
return mesecon.rules . default
end
-- some more general high-level stuff
2017-07-31 00:12:21 +02:00
function mesecon . is_power_on ( pos , rulename )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
if node and ( mesecon.is_conductor_on ( node , rulename ) or is_receptor_on ( node.name ) ) then
2015-06-29 19:55:56 +02:00
return true
end
return false
end
2017-07-31 00:12:21 +02:00
function mesecon . is_power_off ( pos , rulename )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
2017-07-31 00:12:21 +02:00
if node and ( mesecon.is_conductor_off ( node , rulename ) or mesecon.is_receptor_off ( node.name ) ) then
2015-06-29 19:55:56 +02:00
return true
end
return false
end
2017-07-31 00:12:21 +02:00
-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`.
-- Breadth-first search. Map is abstracted away in a voxelmanip.
-- Follow all all conductor paths replacing conductors that were already
-- looked at, activating / changing all effectors along the way.
function mesecon . turnon ( pos , link )
local frontiers = { { pos = pos , link = link } }
local depth = 1
while frontiers [ 1 ] do
local f = table.remove ( frontiers , 1 )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( f.pos )
2017-07-31 00:12:21 +02:00
if not node then
-- Area does not exist; do nothing
elseif mesecon.is_conductor_off ( node , f.link ) then
local rules = mesecon.conductor_get_rules ( node )
-- Call turnon on neighbors
2021-04-09 00:08:03 +02:00
for _ , r in pairs ( mesecon.rule2meta ( f.link , rules ) ) do
2017-07-31 00:12:21 +02:00
local np = vector.add ( f.pos , r )
2021-04-09 00:08:03 +02:00
for _ , l in pairs ( mesecon.rules_link_rule_all ( f.pos , r ) ) do
insert ( frontiers , { pos = np , link = l } )
2017-07-31 00:12:21 +02:00
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
mesecon.swap_node_force ( f.pos , mesecon.get_conductor_on ( node , f.link ) )
elseif mesecon.is_effector ( node.name ) then
mesecon.changesignal ( f.pos , node , f.link , mesecon.state . on , depth )
if mesecon.is_effector_off ( node.name ) then
mesecon.activate ( f.pos , node , f.link , depth )
2015-06-29 19:55:56 +02:00
end
end
2018-01-20 19:04:53 +01:00
if node and f.link . spread and minetest.get_item_group ( node.name , " opaque " ) == 1 then
-- Call turnon on neighbors
-- Warning: A LOT of nodes need to be looked at for this to work
2021-04-09 00:08:03 +02:00
for _ , r in pairs ( mesecon.rule2meta ( f.link , mesecon.rules . mcl_alldirs_spread ) ) do
2018-01-20 19:04:53 +01:00
local np = vector.add ( f.pos , r )
2021-04-09 00:08:03 +02:00
for _ , l in pairs ( mesecon.rules_link_rule_all ( f.pos , r ) ) do
local nlink = copy ( l )
2018-01-20 19:04:53 +01:00
nlink.spread = false
2021-04-09 00:08:03 +02:00
insert ( frontiers , { pos = np , link = nlink } )
2018-01-20 19:04:53 +01:00
end
end
end
2018-01-13 02:20:07 +01:00
2017-07-31 00:12:21 +02:00
depth = depth + 1
2015-06-29 19:55:56 +02:00
end
end
2018-01-20 19:04:53 +01:00
-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`.
2017-07-31 00:12:21 +02:00
-- Breadth-first search. Map is abstracted away in a voxelmanip.
-- Follow all all conductor paths replacing conductors that were already
-- looked at, deactivating / changing all effectors along the way.
-- In case an onstate receptor is discovered, abort the process by returning false, which will
-- cause `receptor_off` to discard all changes made in the voxelmanip.
-- Contrary to turnon, turnoff has to cache all change and deactivate signals so that they will only
-- be called in the very end when we can be sure that no conductor was found along the path.
--
-- Signal table entry structure:
-- {
-- pos = position of effector,
-- node = node descriptor (name, param1 and param2),
-- link = link the effector is connected to,
-- depth = indicates order in which signals wire fired, higher is later
-- }
function mesecon . turnoff ( pos , link )
local frontiers = { { pos = pos , link = link } }
local signals = { }
local depth = 1
while frontiers [ 1 ] do
local f = table.remove ( frontiers , 1 )
2021-04-09 00:08:03 +02:00
local node = get_node_force ( f.pos )
2017-07-31 00:12:21 +02:00
if not node then
2018-01-20 19:55:25 +01:00
-- No-op
2017-07-31 00:12:21 +02:00
elseif mesecon.is_conductor_on ( node , f.link ) then
local rules = mesecon.conductor_get_rules ( node )
2021-04-09 00:08:03 +02:00
for _ , r in pairs ( mesecon.rule2meta ( f.link , rules ) ) do
2017-07-31 00:12:21 +02:00
local np = vector.add ( f.pos , r )
-- Check if an onstate receptor is connected. If that is the case,
-- abort this turnoff process by returning false. `receptor_off` will
-- discard all the changes that we made in the voxelmanip:
2021-04-09 00:08:03 +02:00
for _ , l in pairs ( mesecon.rules_link_rule_all_inverted ( f.pos , r ) ) do
if is_receptor_on ( get_node_force ( np ) . name ) then
2017-07-31 00:12:21 +02:00
return false
end
end
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
-- Call turnoff on neighbors
2021-04-09 00:08:03 +02:00
for _ , l in pairs ( mesecon.rules_link_rule_all ( f.pos , r ) ) do
insert ( frontiers , { pos = np , link = l } )
2017-07-31 00:12:21 +02:00
end
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
mesecon.swap_node_force ( f.pos , mesecon.get_conductor_off ( node , f.link ) )
elseif mesecon.is_effector ( node.name ) then
2021-04-09 00:08:03 +02:00
insert ( signals , {
2017-07-31 00:12:21 +02:00
pos = f.pos ,
node = node ,
link = f.link ,
depth = depth
} )
2015-06-29 19:55:56 +02:00
end
2018-01-20 19:55:25 +01:00
2018-01-20 19:04:53 +01:00
if node and f.link . spread and minetest.get_item_group ( node.name , " opaque " ) == 1 then
2018-01-20 19:55:25 +01:00
-- Call turnoff on neighbors
-- Warning: A LOT of nodes need to be looked at for this to work
2021-04-09 00:08:03 +02:00
local fpos = f.pos
for _ , r in pairs ( mesecon.rule2meta ( f.link , mesecon.rules . mcl_alldirs_spread ) ) do
local np = { x = fpos.x + r.x , y = fpos.y + r.y , z = fpos.z + r.z }
local n = get_node_force ( np )
if n and is_receptor_on ( n.name ) then
local receptorrules = receptor_get_rules ( n )
for _ , rr in pairs ( receptorrules ) do
if rr.spread and equals ( invertRule ( rr ) , r ) then
return false
2018-01-22 16:53:44 +01:00
end
end
2018-01-20 19:55:25 +01:00
end
2021-04-09 00:08:03 +02:00
for _ , l in pairs ( mesecon.rules_link_rule_all ( fpos , r ) ) do
local nlink = copy ( l )
2018-01-20 19:55:25 +01:00
nlink.spread = false
2021-04-09 00:08:03 +02:00
insert ( frontiers , { pos = np , link = nlink } )
2018-01-20 19:55:25 +01:00
end
end
2018-01-20 19:04:53 +01:00
end
2017-07-31 00:12:21 +02:00
depth = depth + 1
2015-06-29 19:55:56 +02:00
end
2021-04-09 00:08:03 +02:00
for _ , sig in pairs ( signals ) do
2017-07-31 00:12:21 +02:00
mesecon.changesignal ( sig.pos , sig.node , sig.link , mesecon.state . off , sig.depth )
if mesecon.is_effector_on ( sig.node . name ) and not mesecon.is_powered ( sig.pos ) then
mesecon.deactivate ( sig.pos , sig.node , sig.link , sig.depth )
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
return true
end
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
-- Get all linking inputrules of inputnode (effector or conductor) that is connected to
-- outputnode (receptor or conductor) at position `output` and has an output in direction `rule`
function mesecon . rules_link_rule_all ( output , rule )
local input = vector.add ( output , rule )
2021-04-09 00:08:03 +02:00
local inputnode = get_node_force ( input )
2017-07-31 00:12:21 +02:00
local inputrules = mesecon.get_any_inputrules ( inputnode )
if not inputrules then
return { }
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
local rules = { }
2015-06-29 19:55:56 +02:00
2021-04-09 00:08:03 +02:00
for _ , inputrule in pairs ( mesecon.flattenrules ( inputrules ) ) do
2017-07-31 00:12:21 +02:00
-- Check if input accepts from output
2021-04-09 00:08:03 +02:00
if equals ( vector.add ( input , inputrule ) , output ) then
local newrule = copy ( inputrule )
2018-01-20 19:04:53 +01:00
newrule.spread = rule.spread
2021-04-09 00:08:03 +02:00
insert ( rules , newrule )
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
return rules
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
-- Get all linking outputnodes of outputnode (receptor or conductor) that is connected to
-- inputnode (effector or conductor) at position `input` and has an input in direction `rule`
function mesecon . rules_link_rule_all_inverted ( input , rule )
local output = vector.add ( input , rule )
2021-04-09 00:08:03 +02:00
local outputnode = get_node_force ( output )
2017-07-31 00:12:21 +02:00
local outputrules = mesecon.get_any_outputrules ( outputnode )
if not outputrules then
return { }
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
local rules = { }
2015-06-29 19:55:56 +02:00
2021-04-09 00:08:03 +02:00
for _ , outputrule in pairs ( mesecon.flattenrules ( outputrules ) ) do
if equals ( vector.add ( output , outputrule ) , input ) then
local newrule = copy ( outputrule )
newrule = invertRule ( newrule )
2018-01-20 19:04:53 +01:00
newrule.spread = rule.spread
2021-04-09 00:08:03 +02:00
insert ( rules , newrule )
2015-06-29 19:55:56 +02:00
end
end
2017-07-31 00:12:21 +02:00
return rules
2015-06-29 19:55:56 +02:00
end
2018-01-17 03:05:12 +01:00
function mesecon . is_powered ( pos , rule , depth , sourcepos , home_pos )
2018-01-17 02:44:00 +01:00
if depth == nil then depth = 0 end
if depth > 1 then
2018-01-17 17:15:08 +01:00
return false , false
2018-01-17 02:44:00 +01:00
end
2021-04-09 00:08:03 +02:00
local node = get_node_force ( pos )
2017-07-31 00:12:21 +02:00
local rules = mesecon.get_any_inputrules ( node )
2018-01-17 02:44:00 +01:00
if not rules then
2018-01-17 17:15:08 +01:00
return false , false
2018-01-17 02:44:00 +01:00
end
2018-01-17 03:05:12 +01:00
if not home_pos then
home_pos = pos
end
2015-06-29 19:55:56 +02:00
2017-07-31 00:12:21 +02:00
-- List of nodes that send out power to pos
2018-01-17 02:44:00 +01:00
if sourcepos == nil then
sourcepos = { }
end
2015-06-29 19:55:56 +02:00
2018-01-17 05:49:11 +01:00
local function power_walk ( pos , home_pos , sourcepos , rulenames , rule , depth )
2018-01-17 20:23:43 +01:00
local spread = false
2021-04-09 00:08:03 +02:00
for _ , rname in pairs ( rulenames ) do
2017-07-31 00:12:21 +02:00
local np = vector.add ( pos , rname )
2021-04-09 00:08:03 +02:00
local nn = get_node_force ( np )
if ( mesecon.is_conductor_on ( nn , invertRule ( rname ) )
or is_receptor_on ( nn.name ) ) then
if not equals ( home_pos , np ) then
2018-01-17 20:20:08 +01:00
local rulez = mesecon.get_any_outputrules ( nn )
2018-01-17 20:23:43 +01:00
local spread_tmp = false
2018-01-17 20:20:08 +01:00
for r = 1 , # rulez do
2021-04-09 00:08:03 +02:00
if equals ( invertRule ( rname ) , rulez [ r ] ) then
2018-01-17 20:20:08 +01:00
if rulez [ r ] . spread then
2018-01-17 20:23:43 +01:00
spread_tmp = true
2018-01-17 20:20:08 +01:00
end
end
end
2018-01-17 20:23:43 +01:00
if depth == 0 or spread_tmp then
2021-04-09 00:08:03 +02:00
insert ( sourcepos , np )
2018-01-17 20:23:43 +01:00
if spread_tmp then
spread = true
2018-01-17 20:20:08 +01:00
end
end
2018-01-17 03:05:12 +01:00
end
2018-01-17 02:44:00 +01:00
elseif depth == 0 and minetest.get_item_group ( nn.name , " opaque " ) == 1 then
2018-01-17 03:05:12 +01:00
local more_sourcepos = mesecon.is_powered ( np , nil , depth + 1 , sourcepos , home_pos )
2018-01-17 03:54:51 +01:00
if more_sourcepos and # more_sourcepos > 0 then
mesecon.mergetable ( sourcepos , more_sourcepos )
end
2017-07-31 00:12:21 +02:00
end
2015-06-29 19:55:56 +02:00
end
2018-01-17 20:23:43 +01:00
return sourcepos , spread
2018-01-17 02:44:00 +01:00
end
2018-01-17 20:23:43 +01:00
local spread = false
2018-01-17 02:44:00 +01:00
if not rule then
2021-04-09 00:08:03 +02:00
for _ , rule in pairs ( mesecon.flattenrules ( rules ) ) do
2018-01-17 20:23:43 +01:00
local spread_temp
2018-01-17 02:44:00 +01:00
local rulenames = mesecon.rules_link_rule_all_inverted ( pos , rule )
2018-01-17 20:23:43 +01:00
sourcepos , spread_temp = power_walk ( pos , home_pos , sourcepos , rulenames , rule , depth )
if spread_temp then
spread = true
2018-01-17 17:15:08 +01:00
end
2018-01-17 02:44:00 +01:00
end
else
local rulenames = mesecon.rules_link_rule_all_inverted ( pos , rule )
2018-01-17 20:23:43 +01:00
sourcepos , spread = power_walk ( pos , home_pos , sourcepos , rulenames , rule , depth )
2015-06-29 19:55:56 +02:00
end
2017-07-31 00:12:21 +02:00
-- Return FALSE if not powered, return list of sources if is powered
2018-01-17 03:54:51 +01:00
if ( # sourcepos == 0 ) then
2018-01-17 17:15:08 +01:00
return false , false
2018-01-17 03:54:51 +01:00
else
2018-01-17 20:23:43 +01:00
return sourcepos , spread
2018-01-17 03:54:51 +01:00
end
2015-06-29 19:55:56 +02:00
end