summaryrefslogtreecommitdiff
path: root/mesecons/mesecons
diff options
context:
space:
mode:
Diffstat (limited to 'mesecons/mesecons')
-rw-r--r--mesecons/mesecons/VERSION1
-rw-r--r--mesecons/mesecons/actionqueue.lua118
-rw-r--r--mesecons/mesecons/depends.txt1
-rw-r--r--mesecons/mesecons/doc/mesecon/description.html1
-rwxr-xr-xmesecons/mesecons/doc/mesecon/preview.pngbin0 -> 29946 bytes
-rw-r--r--mesecons/mesecons/doc/mesecon/recipe.pngbin0 -> 3932 bytes
-rw-r--r--mesecons/mesecons/init.lua139
-rw-r--r--mesecons/mesecons/internal.lua652
-rw-r--r--mesecons/mesecons/legacy.lua30
-rw-r--r--mesecons/mesecons/oldwires.lua38
-rw-r--r--mesecons/mesecons/presets.lua55
-rw-r--r--mesecons/mesecons/services.lua100
-rw-r--r--mesecons/mesecons/settings.lua15
-rw-r--r--mesecons/mesecons/textures/mesecons_wire_inv.pngbin0 -> 204 bytes
-rw-r--r--mesecons/mesecons/textures/mesecons_wire_off.pngbin0 -> 465 bytes
-rw-r--r--mesecons/mesecons/textures/mesecons_wire_on.pngbin0 -> 464 bytes
-rw-r--r--mesecons/mesecons/util.lua211
-rw-r--r--mesecons/mesecons/wires.lua250
18 files changed, 1611 insertions, 0 deletions
diff --git a/mesecons/mesecons/VERSION b/mesecons/mesecons/VERSION
new file mode 100644
index 0000000..75b9e03
--- /dev/null
+++ b/mesecons/mesecons/VERSION
@@ -0,0 +1 @@
+0.41 DEV
diff --git a/mesecons/mesecons/actionqueue.lua b/mesecons/mesecons/actionqueue.lua
new file mode 100644
index 0000000..fa4079f
--- /dev/null
+++ b/mesecons/mesecons/actionqueue.lua
@@ -0,0 +1,118 @@
+mesecon.queue.actions={} -- contains all ActionQueue actions
+
+function mesecon.queue:add_function(name, func)
+ mesecon.queue.funcs[name] = func
+end
+
+-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
+-- use overwritecheck nil to never overwrite, but just add the event to the queue
+-- priority specifies the order actions are executed within one globalstep, highest first
+-- should be between 0 and 1
+function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
+ -- Create Action Table:
+ time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
+ priority = priority or 1
+ local action = { pos=mesecon.tablecopy(pos),
+ func=func,
+ params=mesecon.tablecopy(params or {}),
+ time=time,
+ owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
+ priority=priority}
+
+ local toremove = nil
+ -- Otherwise, add the action to the queue
+ if overwritecheck then -- check if old action has to be overwritten / removed:
+ for i, ac in ipairs(mesecon.queue.actions) do
+ if(mesecon.cmpPos(pos, ac.pos)
+ and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
+ toremove = i
+ break
+ end
+ end
+ end
+
+ if (toremove ~= nil) then
+ table.remove(mesecon.queue.actions, toremove)
+ end
+
+ table.insert(mesecon.queue.actions, action)
+end
+
+-- execute the stored functions on a globalstep
+-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
+-- this makes sure that resuming mesecons circuits when restarting minetest works fine
+-- However, even that does not work in some cases, that's why we delay the time the globalsteps
+-- start to be execute by 5 seconds
+local get_highest_priority = function (actions)
+ local highestp = -1
+ local highesti
+ for i, ac in ipairs(actions) do
+ if ac.priority > highestp then
+ highestp = ac.priority
+ highesti = i
+ end
+ end
+
+ return highesti
+end
+
+local m_time = 0
+local resumetime = mesecon.setting("resumetime", 4)
+minetest.register_globalstep(function (dtime)
+ m_time = m_time + dtime
+ -- don't even try if server has not been running for XY seconds; resumetime = time to wait
+ -- after starting the server before processing the ActionQueue, don't set this too low
+ if (m_time < resumetime) then return end
+ local actions = mesecon.tablecopy(mesecon.queue.actions)
+ local actions_now={}
+
+ mesecon.queue.actions = {}
+
+ -- sort actions into two categories:
+ -- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions)
+ for i, ac in ipairs(actions) do
+ if ac.time > 0 then
+ ac.time = ac.time - dtime -- executed later
+ table.insert(mesecon.queue.actions, ac)
+ else
+ table.insert(actions_now, ac)
+ end
+ end
+
+ while(#actions_now > 0) do -- execute highest priorities first, until all are executed
+ local hp = get_highest_priority(actions_now)
+ mesecon.queue:execute(actions_now[hp])
+ table.remove(actions_now, hp)
+ end
+end)
+
+function mesecon.queue:execute(action)
+ mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
+end
+
+
+-- Store and read the ActionQueue to / from a file
+-- so that upcoming actions are remembered when the game
+-- is restarted
+
+local wpath = minetest.get_worldpath()
+local function file2table(filename)
+ local f = io.open(filename, "r")
+ if f==nil then return {} end
+ local t = f:read("*all")
+ f:close()
+ if t=="" or t==nil then return {} end
+ return minetest.deserialize(t)
+end
+
+local function table2file(filename, table)
+ local f = io.open(filename, "w")
+ f:write(minetest.serialize(table))
+ f:close()
+end
+
+mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue")
+
+minetest.register_on_shutdown(function()
+ mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
+end)
diff --git a/mesecons/mesecons/depends.txt b/mesecons/mesecons/depends.txt
new file mode 100644
index 0000000..4ad96d5
--- /dev/null
+++ b/mesecons/mesecons/depends.txt
@@ -0,0 +1 @@
+default
diff --git a/mesecons/mesecons/doc/mesecon/description.html b/mesecons/mesecons/doc/mesecon/description.html
new file mode 100644
index 0000000..a22ec65
--- /dev/null
+++ b/mesecons/mesecons/doc/mesecon/description.html
@@ -0,0 +1 @@
+ Mesecons are the wires, use them to connect effectors with receptors.
diff --git a/mesecons/mesecons/doc/mesecon/preview.png b/mesecons/mesecons/doc/mesecon/preview.png
new file mode 100755
index 0000000..f81e5cb
--- /dev/null
+++ b/mesecons/mesecons/doc/mesecon/preview.png
Binary files differ
diff --git a/mesecons/mesecons/doc/mesecon/recipe.png b/mesecons/mesecons/doc/mesecon/recipe.png
new file mode 100644
index 0000000..72f9210
--- /dev/null
+++ b/mesecons/mesecons/doc/mesecon/recipe.png
Binary files differ
diff --git a/mesecons/mesecons/init.lua b/mesecons/mesecons/init.lua
new file mode 100644
index 0000000..8645f03
--- /dev/null
+++ b/mesecons/mesecons/init.lua
@@ -0,0 +1,139 @@
+-- |\ /| ____ ____ ____ _____ ____ _____
+-- | \ / | | | | | | | |\ | |
+-- | \/ | |___ ____ |___ | | | | \ | |____
+-- | | | | | | | | | \ | |
+-- | | |___ ____| |___ |____ |____| | \| ____|
+-- by Jeija, Uberi (Temperest), sfan5, VanessaE
+--
+--
+--
+-- This mod adds mesecons[=minecraft redstone] and different receptors/effectors to minetest.
+-- See the documentation on the forum for additional information, especially about crafting
+--
+--
+-- For developer documentation see the Developers' section on mesecons.TK
+--
+--
+--
+--Quick draft for the mesecons array in the node's definition
+--mesecons =
+--{
+-- receptor =
+-- {
+-- state = mesecon.state.on/off
+-- rules = rules/get_rules
+-- },
+-- effector =
+-- {
+-- action_on = function
+-- action_off = function
+-- action_change = function
+-- rules = rules/get_rules
+-- },
+-- conductor =
+-- {
+-- state = mesecon.state.on/off
+-- offstate = opposite state (for state = on only)
+-- onstate = opposite state (for state = off only)
+-- rules = rules/get_rules
+-- }
+--}
+
+-- PUBLIC VARIABLES
+mesecon={} -- contains all functions and all global variables
+mesecon.queue={} -- contains the ActionQueue
+mesecon.queue.funcs={} -- contains all ActionQueue functions
+
+-- Settings
+dofile(minetest.get_modpath("mesecons").."/settings.lua")
+
+-- Utilities like comparing positions,
+-- adding positions and rules,
+-- mostly things that make the source look cleaner
+dofile(minetest.get_modpath("mesecons").."/util.lua");
+
+-- Presets (eg default rules)
+dofile(minetest.get_modpath("mesecons").."/presets.lua");
+
+-- The ActionQueue
+-- Saves all the actions that have to be execute in the future
+dofile(minetest.get_modpath("mesecons").."/actionqueue.lua");
+
+-- Internal stuff
+-- This is the most important file
+-- it handles signal transmission and basically everything else
+-- It is also responsible for managing the nodedef things,
+-- like calling action_on/off/change
+dofile(minetest.get_modpath("mesecons").."/internal.lua");
+
+-- API
+-- these are the only functions you need to remember
+
+mesecon.queue:add_function("receptor_on", function (pos, rules)
+ rules = rules or mesecon.rules.default
+
+ -- if area (any of the rule targets) is not loaded, keep trying and call this again later
+ for _, rule in ipairs(mesecon.flattenrules(rules)) do
+ local np = mesecon.addPosRule(pos, rule)
+ -- if area is not loaded, keep trying
+ if minetest.get_node_or_nil(np) == nil then
+ mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
+ return
+ end
+ end
+
+ -- execute action
+ for _, rule in ipairs(mesecon.flattenrules(rules)) do
+ local np = mesecon.addPosRule(pos, rule)
+ local rulenames = mesecon.rules_link_rule_all(pos, rule)
+ for _, rulename in ipairs(rulenames) do
+ mesecon.turnon(np, rulename)
+ end
+ end
+end)
+
+function mesecon.receptor_on(pos, rules)
+ mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
+end
+
+mesecon.queue:add_function("receptor_off", function (pos, rules)
+ rules = rules or mesecon.rules.default
+
+ -- if area (any of the rule targets) is not loaded, keep trying and call this again later
+ for _, rule in ipairs(mesecon.flattenrules(rules)) do
+ local np = mesecon.addPosRule(pos, rule)
+ if minetest.get_node_or_nil(np) == nil then
+ mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
+ return
+ end
+ end
+
+ for _, rule in ipairs(mesecon.flattenrules(rules)) do
+ local np = mesecon.addPosRule(pos, rule)
+ local rulenames = mesecon.rules_link_rule_all(pos, rule)
+ for _, rulename in ipairs(rulenames) do
+ if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then
+ mesecon.turnoff(np, rulename)
+ else
+ mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
+ end
+ end
+ end
+end)
+
+function mesecon.receptor_off(pos, rules)
+ mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
+end
+
+
+print("[OK] Mesecons")
+
+-- Deprecated stuff
+-- To be removed in future releases
+dofile(minetest.get_modpath("mesecons").."/legacy.lua");
+
+--The actual wires
+dofile(minetest.get_modpath("mesecons").."/wires.lua");
+
+--Services like turnoff receptor on dignode and so on
+dofile(minetest.get_modpath("mesecons").."/services.lua");
diff --git a/mesecons/mesecons/internal.lua b/mesecons/mesecons/internal.lua
new file mode 100644
index 0000000..741abf1
--- /dev/null
+++ b/mesecons/mesecons/internal.lua
@@ -0,0 +1,652 @@
+-- Internal.lua - The core of mesecons
+--
+-- For more practical developer resources see http://mesecons.net/developers.php
+--
+-- Function overview
+-- 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
+
+-- RECEPTORS
+-- 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)
+
+-- EFFECTORS
+-- 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)
+
+-- SIGNALS
+-- 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
+
+-- CONDUCTORS
+-- 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)
+
+-- HIGH-LEVEL Internals
+-- 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
+-- mesecon.turnon(pos, link) --> link is the input rule that caused calling turnon, turns on every connected node, iterative
+-- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative
+-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative
+-- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
+-- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped
+-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
+
+-- RULES ROTATION helpers
+-- mesecon.rotate_rules_right(rules)
+-- mesecon.rotate_rules_left(rules)
+-- mesecon.rotate_rules_up(rules)
+-- mesecon.rotate_rules_down(rules)
+-- These functions return rules that have been rotated in the specific direction
+
+-- General
+function mesecon.get_effector(nodename)
+ if minetest.registered_nodes[nodename]
+ and minetest.registered_nodes[nodename].mesecons
+ and minetest.registered_nodes[nodename].mesecons.effector then
+ return minetest.registered_nodes[nodename].mesecons.effector
+ end
+end
+
+function mesecon.get_receptor(nodename)
+ if minetest.registered_nodes[nodename]
+ and minetest.registered_nodes[nodename].mesecons
+ and minetest.registered_nodes[nodename].mesecons.receptor then
+ return minetest.registered_nodes[nodename].mesecons.receptor
+ end
+end
+
+function mesecon.get_conductor(nodename)
+ if minetest.registered_nodes[nodename]
+ and minetest.registered_nodes[nodename].mesecons
+ and minetest.registered_nodes[nodename].mesecons.conductor then
+ return minetest.registered_nodes[nodename].mesecons.conductor
+ end
+end
+
+function mesecon.get_any_outputrules (node)
+ 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)
+ end
+end
+
+function mesecon.get_any_inputrules (node)
+ 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)
+ end
+end
+
+function mesecon.get_any_rules (node)
+ return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
+ mesecon.get_any_outputrules(node) or {})
+end
+
+-- Receptors
+-- Nodes that can power mesecons
+function mesecon.is_receptor_on(nodename)
+ local receptor = mesecon.get_receptor(nodename)
+ if receptor and receptor.state == mesecon.state.on then
+ return true
+ end
+ return false
+end
+
+function mesecon.is_receptor_off(nodename)
+ local receptor = mesecon.get_receptor(nodename)
+ if receptor and receptor.state == mesecon.state.off then
+ return true
+ end
+ return false
+end
+
+function mesecon.is_receptor(nodename)
+ local receptor = mesecon.get_receptor(nodename)
+ if receptor then
+ return true
+ end
+ return false
+end
+
+function mesecon.receptor_get_rules(node)
+ local receptor = mesecon.get_receptor(node.name)
+ 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
+function mesecon.is_effector_on(nodename)
+ local effector = mesecon.get_effector(nodename)
+ if effector and effector.action_off then
+ return true
+ end
+ return false
+end
+
+function mesecon.is_effector_off(nodename)
+ local effector = mesecon.get_effector(nodename)
+ if effector and effector.action_on then
+ return true
+ end
+ return false
+end
+
+function mesecon.is_effector(nodename)
+ local effector = mesecon.get_effector(nodename)
+ if effector then
+ return true
+ end
+ return false
+end
+
+function mesecon.effector_get_rules(node)
+ local effector = mesecon.get_effector(node.name)
+ 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
+
+-- #######################
+-- # Signals (effectors) #
+-- #######################
+
+-- Activation:
+mesecon.queue:add_function("activate", function (pos, rulename)
+ local node = minetest.get_node(pos)
+ local effector = mesecon.get_effector(node.name)
+
+ if effector and effector.action_on then
+ effector.action_on(pos, node, rulename)
+ end
+end)
+
+function mesecon.activate(pos, node, rulename, depth)
+ if rulename == nil then
+ for _,rule in ipairs(mesecon.effector_get_rules(node)) do
+ mesecon.activate(pos, node, rule, depth + 1)
+ end
+ return
+ end
+ mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth)
+end
+
+
+-- Deactivation
+mesecon.queue:add_function("deactivate", function (pos, rulename)
+ local node = minetest.get_node(pos)
+ local effector = mesecon.get_effector(node.name)
+
+ if effector and effector.action_off then
+ effector.action_off(pos, node, rulename)
+ end
+end)
+
+function mesecon.deactivate(pos, node, rulename, depth)
+ if rulename == nil then
+ for _,rule in ipairs(mesecon.effector_get_rules(node)) do
+ mesecon.deactivate(pos, node, rule, depth + 1)
+ end
+ return
+ end
+ mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth)
+end
+
+
+-- Change
+mesecon.queue:add_function("change", function (pos, rulename, changetype)
+ local node = minetest.get_node(pos)
+ 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
+ for _,rule in ipairs(mesecon.effector_get_rules(node)) do
+ 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)
+end
+
+-- Conductors
+
+function mesecon.is_conductor_on(node, rulename)
+ 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
+ end
+ return false
+end
+
+function mesecon.is_conductor_off(node, rulename)
+ 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
+ end
+ return false
+end
+
+function mesecon.is_conductor(nodename)
+ local conductor = mesecon.get_conductor(nodename)
+ if conductor then
+ return true
+ end
+ return false
+end
+
+function mesecon.get_conductor_on(node_off, rulename)
+ local conductor = mesecon.get_conductor(node_off.name)
+ if conductor then
+ 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
+ end
+ return offstate
+end
+
+function mesecon.get_conductor_off(node_on, rulename)
+ local conductor = mesecon.get_conductor(node_on.name)
+ if conductor then
+ 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
+ end
+ return onstate
+end
+
+function mesecon.conductor_get_rules(node)
+ local conductor = mesecon.get_conductor(node.name)
+ 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
+
+function mesecon.is_power_on(pos, rulename)
+ local node = minetest.get_node(pos)
+ if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then
+ return true
+ end
+ return false
+end
+
+function mesecon.is_power_off(pos, rulename)
+ local node = minetest.get_node(pos)
+ if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then
+ return true
+ end
+ return false
+end
+
+function mesecon.turnon(pos, link)
+ local frontiers = {{pos = pos, link = link}}
+
+ local depth = 1
+ while frontiers[depth] do
+ local f = frontiers[depth]
+ local node = minetest.get_node_or_nil(f.pos)
+
+ -- area not loaded, postpone action
+ if not node then
+ mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true)
+ elseif mesecon.is_conductor_off(node, f.link) then
+ local rules = mesecon.conductor_get_rules(node)
+
+ minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link),
+ param2 = node.param2})
+
+ -- call turnon on neighbors: normal rules
+ for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
+ local np = mesecon.addPosRule(f.pos, r)
+
+ -- area not loaded, postpone action
+ if not minetest.get_node_or_nil(np) then
+ mesecon.queue:add_action(np, "turnon", {rulename},
+ nil, true)
+ else
+ local links = mesecon.rules_link_rule_all(f.pos, r)
+ for _, l in ipairs(links) do
+ table.insert(frontiers, {pos = np, link = l})
+ end
+ end
+ end
+ 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)
+ end
+ end
+ depth = depth + 1
+ end
+end
+
+mesecon.queue:add_function("turnon", function (pos, rulename, recdepth)
+ mesecon.turnon(pos, rulename, recdepth)
+end)
+
+function mesecon.turnoff(pos, link)
+ local frontiers = {{pos = pos, link = link}}
+
+ local depth = 1
+ while frontiers[depth] do
+ local f = frontiers[depth]
+ local node = minetest.get_node_or_nil(f.pos)
+
+ -- area not loaded, postpone action
+ if not node then
+ mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true)
+ elseif mesecon.is_conductor_on(node, f.link) then
+ local rules = mesecon.conductor_get_rules(node)
+
+ minetest.swap_node(f.pos, {name = mesecon.get_conductor_off(node, f.link),
+ param2 = node.param2})
+
+ -- call turnoff on neighbors: normal rules
+ for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
+ local np = mesecon.addPosRule(f.pos, r)
+
+ -- area not loaded, postpone action
+ if not minetest.get_node_or_nil(np) then
+ mesecon.queue:add_action(np, "turnoff", {rulename},
+ nil, true)
+ else
+ local links = mesecon.rules_link_rule_all(f.pos, r)
+ for _, l in ipairs(links) do
+ table.insert(frontiers, {pos = np, link = l})
+ end
+ end
+ end
+ elseif mesecon.is_effector(node.name) then
+ mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth)
+ if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then
+ mesecon.deactivate(f.pos, node, f.link, depth)
+ end
+ end
+ depth = depth + 1
+ end
+end
+
+mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth)
+ mesecon.turnoff(pos, rulename, recdepth)
+end)
+
+
+function mesecon.connected_to_receptor(pos, link)
+ local node = minetest.get_node(pos)
+
+ -- Check if conductors around are connected
+ local rules = mesecon.get_any_inputrules(node)
+ if not rules then return false end
+
+ for _, rule in ipairs(mesecon.rule2meta(link, rules)) do
+ local links = mesecon.rules_link_rule_all_inverted(pos, rule)
+ for _, l in ipairs(links) do
+ local np = mesecon.addPosRule(pos, l)
+ if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
+ return true
+ end
+ end
+ end
+
+ return false
+end
+
+function mesecon.find_receptor_on(pos, link)
+ local frontiers = {{pos = pos, link = link}}
+ local checked = {}
+
+ -- List of positions that have been searched for onstate receptors
+ local depth = 1
+ while frontiers[depth] do
+ local f = frontiers[depth]
+ local node = minetest.get_node_or_nil(f.pos)
+
+ if not node then return false end
+ if mesecon.is_receptor_on(node.name) then return true end
+ if mesecon.is_conductor_on(node, f.link) then
+ local rules = mesecon.conductor_get_rules(node)
+
+ -- call turnoff on neighbors: normal rules
+ for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
+ local np = mesecon.addPosRule(f.pos, r)
+
+ local links = mesecon.rules_link_rule_all_inverted(f.pos, r)
+ for _, l in ipairs(links) do
+ local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z
+ if not checked[checkedstring] then
+ table.insert(frontiers, {pos = np, link = l})
+ checked[checkedstring] = true
+ end
+ end
+ end
+
+ end
+ depth = depth + 1
+ end
+end
+
+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
+ local outputnode = minetest.get_node(output)
+ local inputnode = minetest.get_node(input)
+ local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
+ local inputrules = mesecon.get_any_inputrules (inputnode)
+ if not outputrules or not inputrules then
+ return
+ end
+
+ for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
+ -- Check if output sends to input
+ if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
+ for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
+ -- Check if input accepts from output
+ if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
+ return true, inputrule
+ end
+ end
+ end
+ end
+ return false
+end
+
+function mesecon.rules_link_rule_all(output, rule)
+ local input = mesecon.addPosRule(output, rule)
+ local inputnode = minetest.get_node(input)
+ local inputrules = mesecon.get_any_inputrules (inputnode)
+ if not inputrules then
+ return {}
+ end
+ local rules = {}
+
+ for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
+ -- Check if input accepts from output
+ if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
+ table.insert(rules, inputrule)
+ end
+ end
+ return rules
+end
+
+function mesecon.rules_link_rule_all_inverted(input, rule)
+ --local irule = mesecon.invertRule(rule)
+ local output = mesecon.addPosRule(input, rule)
+ local outputnode = minetest.get_node(output)
+ local outputrules = mesecon.get_any_outputrules (outputnode)
+ if not outputrules then
+ return {}
+ end
+ local rules = {}
+
+ for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
+ if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
+ table.insert(rules, mesecon.invertRule(outputrule))
+ end
+ end
+ return rules
+end
+
+function mesecon.rules_link_anydir(pos1, pos2)
+ return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1)
+end
+
+function mesecon.is_powered(pos, rule)
+ local node = minetest.get_node(pos)
+ local rules = mesecon.get_any_inputrules(node)
+ if not rules then return false end
+
+ -- List of nodes that send out power to pos
+ local sourcepos = {}
+
+ if not rule then
+ for _, rule in ipairs(mesecon.flattenrules(rules)) do
+ local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
+ for _, rname in ipairs(rulenames) do
+ local np = mesecon.addPosRule(pos, rname)
+ local nn = minetest.get_node(np)
+ if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
+ or mesecon.is_receptor_on (nn.name)) then
+ table.insert(sourcepos, np)
+ end
+ end
+ end
+ else
+ local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
+ for _, rname in ipairs(rulenames) do
+ local np = mesecon.addPosRule(pos, rname)
+ local nn = minetest.get_node(np)
+ if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
+ or mesecon.is_receptor_on (nn.name)) then
+ table.insert(sourcepos, np)
+ end
+ end
+ end
+
+ -- Return FALSE if not powered, return list of sources if is powered
+ if (#sourcepos == 0) then return false
+ else return sourcepos end
+end
+
+--Rules rotation Functions:
+function mesecon.rotate_rules_right(rules)
+ local nr = {}
+ for i, rule in ipairs(rules) do
+ table.insert(nr, {
+ x = -rule.z,
+ y = rule.y,
+ z = rule.x,
+ name = rule.name})
+ end
+ return nr
+end
+
+function mesecon.rotate_rules_left(rules)
+ local nr = {}
+ for i, rule in ipairs(rules) do
+ table.insert(nr, {
+ x = rule.z,
+ y = rule.y,
+ z = -rule.x,
+ name = rule.name})
+ end
+ return nr
+end
+
+function mesecon.rotate_rules_down(rules)
+ local nr = {}
+ for i, rule in ipairs(rules) do
+ table.insert(nr, {
+ x = -rule.y,
+ y = rule.x,
+ z = rule.z,
+ name = rule.name})
+ end
+ return nr
+end
+
+function mesecon.rotate_rules_up(rules)
+ local nr = {}
+ for i, rule in ipairs(rules) do
+ table.insert(nr, {
+ x = rule.y,
+ y = -rule.x,
+ z = rule.z,
+ name = rule.name})
+ end
+ return nr
+end
diff --git a/mesecons/mesecons/legacy.lua b/mesecons/mesecons/legacy.lua
new file mode 100644
index 0000000..6d8ccca
--- /dev/null
+++ b/mesecons/mesecons/legacy.lua
@@ -0,0 +1,30 @@
+-- Ugly hack to prevent breaking compatibility with other mods
+-- Just remove the following two functions to delete the hack, to be done when other mods have updated
+function mesecon.receptor_on(self, pos, rules)
+ if (self.receptor_on) then
+ print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
+ print("[Mesecons] If you are the programmer of this mod, please update it ")
+ print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated")
+ print("[Mesecons] Otherwise, please make sure you're running the latest version")
+ print("[Mesecons] of that mod and inform the mod creator.")
+ else
+ rules = pos
+ pos = self
+ end
+ mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
+end
+
+function mesecon.receptor_off(self, pos, rules)
+ if (self.receptor_off) then
+ print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
+ print("[Mesecons] If you are the programmer of this mod, please update it ")
+ print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated")
+ print("[Mesecons] Otherwise, please make sure you're running the latest version")
+ print("[Mesecons] of that mod and inform the mod creator.")
+ else
+ rules = pos
+ pos = self
+ end
+ mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
+end
+
diff --git a/mesecons/mesecons/oldwires.lua b/mesecons/mesecons/oldwires.lua
new file mode 100644
index 0000000..b3b09e5
--- /dev/null
+++ b/mesecons/mesecons/oldwires.lua
@@ -0,0 +1,38 @@
+minetest.register_node("mesecons:mesecon_off", {
+ drawtype = "raillike",
+ tiles = {"jeija_mesecon_off.png", "jeija_mesecon_curved_off.png", "jeija_mesecon_t_junction_off.png", "jeija_mesecon_crossing_off.png"},
+ inventory_image = "jeija_mesecon_off.png",
+ wield_image = "jeija_mesecon_off.png",
+ paramtype = "light",
+ is_ground_content = true,
+ walkable = false,
+ selection_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5},
+ },
+ groups = {dig_immediate=3, mesecon=1, mesecon_conductor_craftable=1},
+ description="Mesecons",
+ mesecons = {conductor={
+ state = mesecon.state.off,
+ onstate = "mesecons:mesecon_on"
+ }}
+})
+
+minetest.register_node("mesecons:mesecon_on", {
+ drawtype = "raillike",
+ tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"},
+ paramtype = "light",
+ is_ground_content = true,
+ walkable = false,
+ selection_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5},
+ },
+ groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1},
+ drop = "mesecons:mesecon_off 1",
+ light_source = default.LIGHT_MAX-11,
+ mesecons = {conductor={
+ state = mesecon.state.on,
+ offstate = "mesecons:mesecon_off"
+ }}
+})
diff --git a/mesecons/mesecons/presets.lua b/mesecons/mesecons/presets.lua
new file mode 100644
index 0000000..2f2f643
--- /dev/null
+++ b/mesecons/mesecons/presets.lua
@@ -0,0 +1,55 @@
+mesecon.rules = {}
+mesecon.state = {}
+
+mesecon.rules.default =
+{{x=0, y=0, z=-1},
+ {x=1, y=0, z=0},
+ {x=-1, y=0, z=0},
+ {x=0, y=0, z=1},
+ {x=1, y=1, z=0},
+ {x=1, y=-1, z=0},
+ {x=-1, y=1, z=0},
+ {x=-1, y=-1, z=0},
+ {x=0, y=1, z=1},
+ {x=0, y=-1, z=1},
+ {x=0, y=1, z=-1},
+ {x=0, y=-1, z=-1}}
+
+mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}})
+
+mesecon.rules.buttonlike =
+{{x = 1, y = 0, z = 0},
+ {x = 1, y = 1, z = 0},
+ {x = 1, y =-1, z = 0},
+ {x = 1, y =-1, z = 1},
+ {x = 1, y =-1, z =-1},
+ {x = 2, y = 0, z = 0}}
+
+mesecon.rules.flat =
+{{x = 1, y = 0, z = 0},
+ {x =-1, y = 0, z = 0},
+ {x = 0, y = 0, z = 1},
+ {x = 0, y = 0, z =-1}}
+
+mesecon.rules.alldirs =
+{{x= 1, y= 0, z= 0},
+ {x=-1, y= 0, z= 0},
+ {x= 0, y= 1, z= 0},
+ {x= 0, y=-1, z= 0},
+ {x= 0, y= 0, z= 1},
+ {x= 0, y= 0, z=-1}}
+
+mesecon.rules.buttonlike_get = function(node)
+ local rules = mesecon.rules.buttonlike
+ if node.param2 == 2 then
+ rules=mesecon.rotate_rules_left(rules)
+ elseif node.param2 == 3 then
+ rules=mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules))
+ elseif node.param2 == 0 then
+ rules=mesecon.rotate_rules_right(rules)
+ end
+ return rules
+end
+
+mesecon.state.on = "on"
+mesecon.state.off = "off"
diff --git a/mesecons/mesecons/services.lua b/mesecons/mesecons/services.lua
new file mode 100644
index 0000000..215fb31
--- /dev/null
+++ b/mesecons/mesecons/services.lua
@@ -0,0 +1,100 @@
+-- Dig and place services
+
+mesecon.on_placenode = function (pos, node)
+ mesecon.update_autoconnect(pos, node)
+
+ -- Receptors: Send on signal when active
+ if mesecon.is_receptor_on(node.name) then
+ mesecon.receptor_on(pos, mesecon.receptor_get_rules(node))
+ end
+
+ -- Conductors: Send turnon signal when powered or replace by respective offstate conductor
+ -- if placed conductor is an onstate one
+ if mesecon.is_conductor(node.name) then
+ local sources = mesecon.is_powered(pos)
+ if sources then
+ -- also call receptor_on if itself is powered already, so that neighboring
+ -- conductors will be activated (when pushing an on-conductor with a piston)
+ for _, s in ipairs(sources) do
+ local rule = {x = pos.x - s.x, y = pos.y - s.y, z = pos.z - s.z}
+ mesecon.turnon(pos, rule)
+ end
+ --mesecon.receptor_on (pos, mesecon.conductor_get_rules(node))
+ elseif mesecon.is_conductor_on(node) then
+ minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)})
+ end
+ end
+
+ -- Effectors: Send changesignal and activate or deactivate
+ if mesecon.is_effector(node.name) then
+ local powered_rules = {}
+ local unpowered_rules = {}
+
+ -- for each input rule, check if powered
+ for _, r in ipairs(mesecon.effector_get_rules(node)) do
+ local powered = mesecon.is_powered(pos, r)
+ if powered then table.insert(powered_rules, r)
+ else table.insert(unpowered_rules, r) end
+
+ local state = powered and mesecon.state.on or mesecon.state.off
+ mesecon.changesignal(pos, node, r, state, 1)
+ end
+
+ if (#powered_rules > 0) then
+ for _, r in ipairs(powered_rules) do
+ mesecon.activate(pos, node, r, 1)
+ end
+ else
+ for _, r in ipairs(unpowered_rules) do
+ mesecon.deactivate(pos, node, r, 1)
+ end
+ end
+ end
+end
+
+mesecon.on_dignode = function (pos, node)
+ if mesecon.is_conductor_on(node) then
+ mesecon.receptor_off(pos, mesecon.conductor_get_rules(node))
+ elseif mesecon.is_receptor_on(node.name) then
+ mesecon.receptor_off(pos, mesecon.receptor_get_rules(node))
+ end
+ mesecon.queue:add_action(pos, "update_autoconnect", {node})
+end
+
+mesecon.queue:add_function("update_autoconnect", mesecon.update_autoconnect)
+
+minetest.register_on_placenode(mesecon.on_placenode)
+minetest.register_on_dignode(mesecon.on_dignode)
+
+-- Overheating service for fast circuits
+
+-- returns true if heat is too high
+mesecon.do_overheat = function(pos)
+ local meta = minetest.get_meta(pos)
+ local heat = meta:get_int("heat") or 0
+
+ heat = heat + 1
+ meta:set_int("heat", heat)
+
+ if heat < mesecon.setting("overheat_max", 20) then
+ mesecon.queue:add_action(pos, "cooldown", {}, 1, nil, 0)
+ else
+ return true
+ end
+
+ return false
+end
+
+
+mesecon.queue:add_function("cooldown", function (pos)
+ if minetest.get_item_group(minetest.get_node(pos).name, "overheat") == 0 then
+ return -- node has been moved, this one does not use overheating - ignore
+ end
+
+ local meta = minetest.get_meta(pos)
+ local heat = meta:get_int("heat")
+
+ if (heat > 0) then
+ meta:set_int("heat", heat - 1)
+ end
+end)
diff --git a/mesecons/mesecons/settings.lua b/mesecons/mesecons/settings.lua
new file mode 100644
index 0000000..50240c3
--- /dev/null
+++ b/mesecons/mesecons/settings.lua
@@ -0,0 +1,15 @@
+-- SETTINGS
+function mesecon.setting(setting, default)
+ if type(default) == "boolean" then
+ local read = minetest.setting_getbool("mesecon."..setting)
+ if read == nil then
+ return default
+ else
+ return read
+ end
+ elseif type(default) == "string" then
+ return minetest.setting_get("mesecon."..setting) or default
+ elseif type(default) == "number" then
+ return tonumber(minetest.setting_get("mesecon."..setting) or default)
+ end
+end
diff --git a/mesecons/mesecons/textures/mesecons_wire_inv.png b/mesecons/mesecons/textures/mesecons_wire_inv.png
new file mode 100644
index 0000000..a3930cb
--- /dev/null
+++ b/mesecons/mesecons/textures/mesecons_wire_inv.png
Binary files differ
diff --git a/mesecons/mesecons/textures/mesecons_wire_off.png b/mesecons/mesecons/textures/mesecons_wire_off.png
new file mode 100644
index 0000000..58164fa
--- /dev/null
+++ b/mesecons/mesecons/textures/mesecons_wire_off.png
Binary files differ
diff --git a/mesecons/mesecons/textures/mesecons_wire_on.png b/mesecons/mesecons/textures/mesecons_wire_on.png
new file mode 100644
index 0000000..98a86c8
--- /dev/null
+++ b/mesecons/mesecons/textures/mesecons_wire_on.png
Binary files differ
diff --git a/mesecons/mesecons/util.lua b/mesecons/mesecons/util.lua
new file mode 100644
index 0000000..dd33f1c
--- /dev/null
+++ b/mesecons/mesecons/util.lua
@@ -0,0 +1,211 @@
+function mesecon.move_node(pos, newpos)
+ local node = minetest.get_node(pos)
+ local meta = minetest.get_meta(pos):to_table()
+ minetest.remove_node(pos)
+ minetest.add_node(newpos, node)
+ minetest.get_meta(pos):from_table(meta)
+end
+
+function mesecon.flattenrules(allrules)
+--[[
+ {
+ {
+ {xyz},
+ {xyz},
+ },
+ {
+ {xyz},
+ {xyz},
+ },
+ }
+--]]
+ if allrules[1] and
+ allrules[1].x then
+ return allrules
+ end
+
+ local shallowrules = {}
+ for _, metarule in ipairs( allrules) do
+ for _, rule in ipairs(metarule ) do
+ table.insert(shallowrules, rule)
+ end
+ end
+ return shallowrules
+--[[
+ {
+ {xyz},
+ {xyz},
+ {xyz},
+ {xyz},
+ }
+--]]
+end
+
+function mesecon.rule2bit(findrule, allrules)
+ --get the bit of the metarule the rule is in, or bit 1
+ if (allrules[1] and
+ allrules[1].x) or
+ not findrule then
+ return 1
+ end
+ for m,metarule in ipairs( allrules) do
+ for _, rule in ipairs(metarule ) do
+ if mesecon.cmpPos(findrule, rule) then
+ return m
+ end
+ end
+ end
+end
+
+function mesecon.rule2metaindex(findrule, allrules)
+ --get the metarule the rule is in, or allrules
+ if allrules[1].x then
+ return nil
+ end
+
+ if not(findrule) then
+ return mesecon.flattenrules(allrules)
+ end
+
+ for m, metarule in ipairs( allrules) do
+ for _, rule in ipairs(metarule ) do
+ if mesecon.cmpPos(findrule, rule) then
+ return m
+ end
+ end
+ end
+end
+
+function mesecon.rule2meta(findrule, allrules)
+ if #allrules == 0 then return {} end
+
+ local index = mesecon.rule2metaindex(findrule, allrules)
+ if index == nil then
+ if allrules[1].x then
+ return allrules
+ else
+ return {}
+ end
+ end
+ return allrules[index]
+end
+
+function mesecon.dec2bin(n)
+ local x, y = math.floor(n / 2), n % 2
+ if (n > 1) then
+ return mesecon.dec2bin(x)..y
+ else
+ return ""..y
+ end
+end
+
+function mesecon.getstate(nodename, states)
+ for state, name in ipairs(states) do
+ if name == nodename then
+ return state
+ end
+ end
+ error(nodename.." doesn't mention itself in "..dump(states))
+end
+
+function mesecon.getbinstate(nodename, states)
+ return mesecon.dec2bin(mesecon.getstate(nodename, states)-1)
+end
+
+function mesecon.get_bit(binary,bit)
+ bit = bit or 1
+ local c = binary:len()-(bit-1)
+ return binary:sub(c,c) == "1"
+end
+
+function mesecon.set_bit(binary,bit,value)
+ if value == "1" then
+ if not mesecon.get_bit(binary,bit) then
+ return mesecon.dec2bin(tonumber(binary,2)+math.pow(2,bit-1))
+ end
+ elseif value == "0" then
+ if mesecon.get_bit(binary,bit) then
+ return mesecon.dec2bin(tonumber(binary,2)-math.pow(2,bit-1))
+ end
+ end
+ return binary
+
+end
+
+function mesecon.invertRule(r)
+ return {x = -r.x, y = -r.y, z = -r.z}
+end
+
+function mesecon.addPosRule(p, r)
+ return {x = p.x + r.x, y = p.y + r.y, z = p.z + r.z}
+end
+
+function mesecon.cmpPos(p1, p2)
+ return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
+end
+
+function mesecon.tablecopy(table) -- deep table copy
+ if type(table) ~= "table" then return table end -- no need to copy
+ local newtable = {}
+
+ for idx, item in pairs(table) do
+ if type(item) == "table" then
+ newtable[idx] = mesecon.tablecopy(item)
+ else
+ newtable[idx] = item
+ end
+ end
+
+ return newtable
+end
+
+function mesecon.cmpAny(t1, t2)
+ if type(t1) ~= type(t2) then return false end
+ if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end
+
+ for i, e in pairs(t1) do
+ if not mesecon.cmpAny(e, t2[i]) then return false end
+ end
+
+ return true
+end
+
+-- does not overwrite values; number keys (ipairs) are appended, not overwritten
+function mesecon.mergetable(source, dest)
+ local rval = mesecon.tablecopy(dest)
+
+ for k, v in pairs(source) do
+ rval[k] = dest[k] or mesecon.tablecopy(v)
+ end
+ for i, v in ipairs(source) do
+ table.insert(rval, mesecon.tablecopy(v))
+ end
+
+ return rval
+end
+
+function mesecon.register_node(name, spec_common, spec_off, spec_on)
+ spec_common.drop = spec_common.drop or name .. "_off"
+ spec_common.__mesecon_basename = name
+ spec_on.__mesecon_state = "on"
+ spec_off.__mesecon_state = "off"
+
+ spec_on = mesecon.mergetable(spec_common, spec_on);
+ spec_off = mesecon.mergetable(spec_common, spec_off);
+
+ minetest.register_node(name .. "_on", spec_on)
+ minetest.register_node(name .. "_off", spec_off)
+end
+
+-- swap onstate and offstate nodes, returns new state
+function mesecon.flipstate(pos, node)
+ local nodedef = minetest.registered_nodes[node.name]
+ local newstate
+ if (nodedef.__mesecon_state == "on") then newstate = "off" end
+ if (nodedef.__mesecon_state == "off") then newstate = "on" end
+
+ minetest.swap_node(pos, {name = nodedef.__mesecon_basename .. "_" .. newstate,
+ param2 = node.param2})
+
+ return newstate
+end
diff --git a/mesecons/mesecons/wires.lua b/mesecons/mesecons/wires.lua
new file mode 100644
index 0000000..18ae8f5
--- /dev/null
+++ b/mesecons/mesecons/wires.lua
@@ -0,0 +1,250 @@
+-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off
+-- where x= x direction, z= z direction, y= y direction, p = +1, m = -1, e.g. xpym = {x=1, y=-1, z=0}
+-- The (xp)/(zpyp)/.. statements shall be replaced by either 0 or 1
+-- Where 0 means the wire has no visual connection to that direction and
+-- 1 means that the wire visually connects to that other node.
+
+-- #######################
+-- ## Update wire looks ##
+-- #######################
+
+-- self_pos = pos of any mesecon node, from_pos = pos of conductor to getconnect for
+local wire_getconnect = function (from_pos, self_pos)
+ local node = minetest.get_node(self_pos)
+ if minetest.registered_nodes[node.name]
+ and minetest.registered_nodes[node.name].mesecons then
+ -- rules of node to possibly connect to
+ local rules = {}
+ if (minetest.registered_nodes[node.name].mesecon_wire) then
+ rules = mesecon.rules.default
+ else
+ rules = mesecon.get_any_rules(node)
+ end
+
+ for _, r in ipairs(mesecon.flattenrules(rules)) do
+ if (mesecon.cmpPos(mesecon.addPosRule(self_pos, r), from_pos)) then
+ return true
+ end
+ end
+ end
+ return false
+end
+
+-- Update this node
+local wire_updateconnect = function (pos)
+ local connections = {}
+
+ for _, r in ipairs(mesecon.rules.default) do
+ if wire_getconnect(pos, mesecon.addPosRule(pos, r)) then
+ table.insert(connections, r)
+ end
+ end
+
+ local nid = {}
+ for _, vec in ipairs(connections) do
+ -- flat component
+ if vec.x == 1 then nid[0] = "1" end
+ if vec.z == 1 then nid[1] = "1" end
+ if vec.x == -1 then nid[2] = "1" end
+ if vec.z == -1 then nid[3] = "1" end
+
+ -- slopy component
+ if vec.y == 1 then
+ if vec.x == 1 then nid[4] = "1" end
+ if vec.z == 1 then nid[5] = "1" end
+ if vec.x == -1 then nid[6] = "1" end
+ if vec.z == -1 then nid[7] = "1" end
+ end
+ end
+
+ local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0")
+ ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0")
+
+ local state_suffix = string.find(minetest.get_node(pos).name, "_off") and "_off" or "_on"
+ minetest.set_node(pos, {name = "mesecons:wire_"..nodeid..state_suffix})
+end
+
+local update_on_place_dig = function (pos, node)
+ -- Update placed node (get_node again as it may have been dug)
+ local nn = minetest.get_node(pos)
+ if (minetest.registered_nodes[nn.name])
+ and (minetest.registered_nodes[nn.name].mesecon_wire) then
+ wire_updateconnect(pos)
+ end
+
+ -- Update nodes around it
+ local rules = {}
+ if minetest.registered_nodes[node.name]
+ and minetest.registered_nodes[node.name].mesecon_wire then
+ rules = mesecon.rules.default
+ else
+ rules = mesecon.get_any_rules(node)
+ end
+ if (not rules) then return end
+
+ for _, r in ipairs(mesecon.flattenrules(rules)) do
+ local np = mesecon.addPosRule(pos, r)
+ if minetest.registered_nodes[minetest.get_node(np).name]
+ and minetest.registered_nodes[minetest.get_node(np).name].mesecon_wire then
+ wire_updateconnect(np)
+ end
+ end
+end
+
+function mesecon.update_autoconnect(pos, node)
+ if (not node) then node = minetest.get_node(pos) end
+ update_on_place_dig(pos, node)
+end
+
+-- ############################
+-- ## Wire node registration ##
+-- ############################
+-- Nodeboxes:
+local box_center = {-1/16, -.5, -1/16, 1/16, -.5+1/16, 1/16}
+local box_bump1 = { -2/16, -8/16, -2/16, 2/16, -13/32, 2/16 }
+
+local nbox_nid =
+{
+ [0] = {1/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}, -- x positive
+ [1] = {-1/16, -.5, 1/16, 1/16, -.5+1/16, 8/16}, -- z positive
+ [2] = {-8/16, -.5, -1/16, -1/16, -.5+1/16, 1/16}, -- x negative
+ [3] = {-1/16, -.5, -8/16, 1/16, -.5+1/16, -1/16}, -- z negative
+
+ [4] = {.5-1/16, -.5+1/16, -1/16, .5, .4999+1/16, 1/16}, -- x positive up
+ [5] = {-1/16, -.5+1/16, .5-1/16, 1/16, .4999+1/16, .5}, -- z positive up
+ [6] = {-.5, -.5+1/16, -1/16, -.5+1/16, .4999+1/16, 1/16}, -- x negative up
+ [7] = {-1/16, -.5+1/16, -.5, 1/16, .4999+1/16, -.5+1/16} -- z negative up
+}
+
+local tiles_off = { "mesecons_wire_off.png" }
+local tiles_on = { "mesecons_wire_on.png" }
+
+local selectionbox =
+{
+ type = "fixed",
+ fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5}
+}
+
+-- go to the next nodeid (ex.: 01000011 --> 01000100)
+local nid_inc = function() end
+nid_inc = function (nid)
+ local i = 0
+ while nid[i-1] ~= 1 do
+ nid[i] = (nid[i] ~= 1) and 1 or 0
+ i = i + 1
+ end
+
+ -- BUT: Skip impossible nodeids:
+ if ((nid[0] == 0 and nid[4] == 1) or (nid[1] == 0 and nid[5] == 1)
+ or (nid[2] == 0 and nid[6] == 1) or (nid[3] == 0 and nid[7] == 1)) then
+ return nid_inc(nid)
+ end
+
+ return i <= 8
+end
+
+register_wires = function()
+ local nid = {}
+ while true do
+ -- Create group specifiction and nodeid string (see note above for details)
+ local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0")
+ ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0")
+
+ -- Calculate nodebox
+ local nodebox = {type = "fixed", fixed={box_center}}
+ for i=0,7 do
+ if nid[i] == 1 then
+ table.insert(nodebox.fixed, nbox_nid[i])
+ end
+ end
+
+ -- Add bump to nodebox if curved
+ if (nid[0] == 1 and nid[1] == 1) or (nid[1] == 1 and nid[2] == 1)
+ or (nid[2] == 1 and nid[3] == 1) or (nid[3] == 1 and nid[0] == 1) then
+ table.insert(nodebox.fixed, box_bump1)
+ end
+
+ -- If nothing to connect to, still make a nodebox of a straight wire
+ if nodeid == "00000000" then
+ nodebox.fixed = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}
+ end
+
+ local rules = {}
+ if (nid[0] == 1) then table.insert(rules, vector.new( 1, 0, 0)) end
+ if (nid[1] == 1) then table.insert(rules, vector.new( 0, 0, 1)) end
+ if (nid[2] == 1) then table.insert(rules, vector.new(-1, 0, 0)) end
+ if (nid[3] == 1) then table.insert(rules, vector.new( 0, 0, -1)) end
+
+ if (nid[0] == 1) then table.insert(rules, vector.new( 1, -1, 0)) end
+ if (nid[1] == 1) then table.insert(rules, vector.new( 0, -1, 1)) end
+ if (nid[2] == 1) then table.insert(rules, vector.new(-1, -1, 0)) end
+ if (nid[3] == 1) then table.insert(rules, vector.new( 0, -1, -1)) end
+
+ if (nid[4] == 1) then table.insert(rules, vector.new( 1, 1, 0)) end
+ if (nid[5] == 1) then table.insert(rules, vector.new( 0, 1, 1)) end
+ if (nid[6] == 1) then table.insert(rules, vector.new(-1, 1, 0)) end
+ if (nid[7] == 1) then table.insert(rules, vector.new( 0, 1, -1)) end
+
+ local meseconspec_off = { conductor = {
+ rules = rules,
+ state = mesecon.state.off,
+ onstate = "mesecons:wire_"..nodeid.."_on"
+ }}
+
+ local meseconspec_on = { conductor = {
+ rules = rules,
+ state = mesecon.state.on,
+ offstate = "mesecons:wire_"..nodeid.."_off"
+ }}
+
+ local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1,
+ not_in_creative_inventory = 1}
+ local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1}
+ if nodeid ~= "00000000" then
+ groups_off["not_in_creative_inventory"] = 1
+ end
+
+ mesecon.register_node("mesecons:wire_"..nodeid, {
+ description = "Mesecon",
+ drawtype = "nodebox",
+ inventory_image = "mesecons_wire_inv.png",
+ wield_image = "mesecons_wire_inv.png",
+ paramtype = "light",
+ paramtype2 = "facedir",
+ sunlight_propagates = true,
+ selection_box = selectionbox,
+ node_box = nodebox,
+ walkable = false,
+ drop = "mesecons:wire_00000000_off",
+ mesecon_wire = true
+ }, {tiles = tiles_off, mesecons = meseconspec_off, groups = groups_off},
+ {tiles = tiles_on, mesecons = meseconspec_on, groups = groups_on})
+
+ if (nid_inc(nid) == false) then return end
+ end
+end
+register_wires()
+
+-- ##############
+-- ## Crafting ##
+-- ##############
+minetest.register_craft({
+ type = "cooking",
+ output = "mesecons:wire_00000000_off 2",
+ recipe = "default:mese_crystal_fragment",
+ cooktime = 3,
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "mesecons:wire_00000000_off 18",
+ recipe = "default:mese_crystal",
+ cooktime = 15,
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "mesecons:wire_00000000_off 162",
+ recipe = "default:mese",
+ cooktime = 30,
+})