Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
966f9a56a6 | |||
30c28d882f | |||
78782c9b2b | |||
51cf528732 |
30
COPYING.txt
@ -1,30 +0,0 @@
|
||||
The Mesecons Mod for Minetest is
|
||||
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
|
||||
|
||||
See the version control system log for information about other authors.
|
||||
|
||||
License of source code
|
||||
----------------------
|
||||
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
|
||||
|
||||
This program is free software; you can redistribute the Mesecons Mod and/or
|
||||
modify it under the terms of the GNU Lesser General Public License version 3
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
License of media (textures, sounds and documentation)
|
||||
-----------------------------------------------------
|
||||
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
|
||||
|
||||
All textures, sounds and documentation files are licensed under the
|
||||
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
11
README.md
@ -22,9 +22,9 @@ OK, I want in.
|
||||
--------------
|
||||
Go get it!
|
||||
|
||||
[DOWNLOAD IT NOW](https://github.com/minetest-mods/mesecons/archive/master.zip)
|
||||
[DOWNLOADS PAGE](http://mesecons.net/downloads.php)
|
||||
|
||||
Now go ahead and install it like any other Minetest mod. Don't know how? Check out [the wonderful page about it](https://wiki.minetest.net/Mods) over at the official Minetest Wiki. For your convenience, here's a quick summary:
|
||||
Now go ahead and install it like any other Minetest mod. Don't know how? Check out [the wonderful page about it](http://wiki.minetest.com/wiki/Mods) over at the Minetest Wiki. For your convenience, here's a quick summary:
|
||||
|
||||
1. If Mesecons is still in a ZIP file, extract the folder inside to somewhere on the computer.
|
||||
2. Make sure that when you open the folder, you can directly find `README.md` in the listing. If you just see another folder, move that folder up one level and delete the old one.
|
||||
@ -39,15 +39,13 @@ How do I use this thing?
|
||||
------------------------
|
||||
How about a [quick overview video](https://www.youtube.com/watch?v=6kmeQj6iW5k)?
|
||||
|
||||
Or maybe a [comprehensive reference](http://mesecons.net/items.html) is your style?
|
||||
Or maybe a [comprehensive reference](http://mesecons.net/items.php) is your style?
|
||||
|
||||
An overview for the very newest of new beginners? How does [this one](http://uberi.mesecons.net/projects/MeseconsBasics/index.html) look?
|
||||
|
||||
There is also a [wiki page](https://wiki.minetest.net/Mods/Mesecons) dedicated to this mod.
|
||||
|
||||
Want to get more into building? Why not check out the [Mesecons Laboratory](http://uberi.mesecons.net/), a website dedicated to advanced Mesecons builders?
|
||||
|
||||
Want to contribute to Mesecons itself? Check out the [source code](https://github.com/minetest-mods/mesecons)!
|
||||
Want to contribute to Mesecons itself? Check out the [source code](https://github.com/Jeija/minetest-mod-mesecons)!
|
||||
|
||||
Who wrote it anyways?
|
||||
---------------------
|
||||
@ -55,7 +53,6 @@ These awesome people made Mesecons possible!
|
||||
|
||||
| Contributor | Contribution |
|
||||
| --------------- | -------------------------------- |
|
||||
| Hawk777 | Code for VoxelManip caching |
|
||||
| Jat15 | Various tweaks. |
|
||||
| Jeija | **Main developer! Everything.** |
|
||||
| Jordach | Noteblock sounds. |
|
||||
|
12
bower.json
@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "mesecons",
|
||||
"description": "Mesecons is a mod for Minetest that implements items related to digital circuitry: wires, buttons, lights, and programmable controllers.",
|
||||
"homepage": "http://mesecons.net",
|
||||
"authors": "Jeija",
|
||||
"license": "LGPL-3.0+",
|
||||
"keywords": [
|
||||
"mesecons",
|
||||
"minetest",
|
||||
"mod"
|
||||
]
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
"Conductors" : {
|
||||
"Mesecon" : "mesecons_wires/doc/mesecon",
|
||||
"Insulated Wire" : "mesecons_insulated/doc/insulated",
|
||||
"T-Junction" : "mesecons_extrawires/doc/tjunction",
|
||||
"Crossing" : "mesecons_extrawires/doc/crossing",
|
||||
"Corner" : "mesecons_extrawires/doc/corner",
|
||||
"Vertical Wire" : "mesecons_extrawires/doc/vertical",
|
||||
"Mese" : "mesecons_extrawires/doc/mese"
|
||||
},
|
||||
"Receptors" : {
|
||||
"Power Plant" : "mesecons_powerplant/doc/powerplant",
|
||||
"Blinky Plant" : "mesecons_blinkyplant/doc/blinkyplant",
|
||||
"Switch" : "mesecons_switch/doc/switch",
|
||||
"Object Detector" : "mesecons_detector/doc/objectdetector",
|
||||
"Node Detector" : "mesecons_detector/doc/nodedetector",
|
||||
"Wall Lever" : "mesecons_walllever/doc/walllever",
|
||||
"Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_wood",
|
||||
"Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_stone",
|
||||
"Water Turbine" : "mesecons_hydroturbine/doc/waterturbine",
|
||||
"Solar Panel" : "mesecons_solarpanel/doc/solarpanel",
|
||||
"Wall Button" : "mesecons_button/doc/button"
|
||||
},
|
||||
"Effectors" : {
|
||||
"Noteblock" : "mesecons_noteblock/doc/noteblock",
|
||||
"Lamp" : "mesecons_lamp/doc/lamp",
|
||||
"Piston" : "mesecons_pistons/doc/piston",
|
||||
"Sticky Piston" : "mesecons_pistons/doc/piston_sticky",
|
||||
"Movestone" : "mesecons_movestones/doc/movestone",
|
||||
"Sticky Movestone" : "mesecons_movestones/doc/movestone_sticky",
|
||||
"Removestone" : "mesecons_random/doc/removestone",
|
||||
"Ghoststone" : "mesecons_random/doc/ghoststone",
|
||||
"Command Block" : "mesecons_commandblock/doc/commandblock",
|
||||
"Lightstones" : {
|
||||
"Dark Grey" : "mesecons_lightstone/doc/lightstone_darkgrey",
|
||||
"Light Grey" : "mesecons_lightstone/doc/lightstone_lightgrey",
|
||||
"Green" : "mesecons_lightstone/doc/lightstone_green",
|
||||
"Red" : "mesecons_lightstone/doc/lightstone_red",
|
||||
"Blue" : "mesecons_lightstone/doc/lightstone_blue",
|
||||
"Yellow" : "mesecons_lightstone/doc/lightstone_yellow"
|
||||
}
|
||||
},
|
||||
"Logic" : {
|
||||
"Luacontroller" : "mesecons_luacontroller/doc/luacontroller",
|
||||
"FPGA" : "mesecons_fpga/doc/fpga",
|
||||
"FPGA Programmer" : "mesecons_fpga/doc/programmer",
|
||||
"Torch" : "mesecons_torch/doc/torch",
|
||||
"Delayer" : "mesecons_delayer/doc/delayer",
|
||||
"Gates" : {
|
||||
"Diode" : "mesecons_gates/doc/diode",
|
||||
"NOT Gate" : "mesecons_gates/doc/not",
|
||||
"AND Gate" : "mesecons_gates/doc/and",
|
||||
"NAND Gate" : "mesecons_gates/doc/nand",
|
||||
"OR Gate" : "mesecons_gates/doc/or",
|
||||
"NOR Gate" : "mesecons_gates/doc/nor",
|
||||
"XOR Gate" : "mesecons_gates/doc/xor"
|
||||
}
|
||||
},
|
||||
"Crafts" : {
|
||||
"Silicon" : "mesecons_materials/doc/silicon",
|
||||
"Glue" : "mesecons_materials/doc/glue",
|
||||
"Fiber" : "mesecons_materials/doc/fiber"
|
||||
}
|
||||
}
|
1
mesecons/VERSION
Normal file
@ -0,0 +1 @@
|
||||
0.41 DEV
|
@ -23,7 +23,7 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior
|
||||
-- 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(vector.equals(pos, ac.pos)
|
||||
if(mesecon.cmpPos(pos, ac.pos)
|
||||
and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
|
||||
toremove = i
|
||||
break
|
||||
@ -87,19 +87,32 @@ minetest.register_globalstep(function (dtime)
|
||||
end)
|
||||
|
||||
function mesecon.queue:execute(action)
|
||||
-- ignore if action queue function name doesn't exist,
|
||||
-- (e.g. in case the action queue savegame was written by an old mesecons version)
|
||||
if mesecon.queue.funcs[action.func] then
|
||||
mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
|
||||
end
|
||||
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
|
||||
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||
|
||||
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.table2file("mesecon_actionqueue", mesecon.queue.actions)
|
||||
mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
|
||||
end)
|
||||
|
@ -3,7 +3,7 @@
|
||||
-- | \/ | |___ ____ |___ | | | | \ | |____
|
||||
-- | | | | | | | | | \ | |
|
||||
-- | | |___ ____| |___ |____ |____| | \| ____|
|
||||
-- by Jeija, Uberi (Temperest), sfan5, VanessaE, Hawk777 and contributors
|
||||
-- by Jeija, Uberi (Temperest), sfan5, VanessaE
|
||||
--
|
||||
--
|
||||
--
|
||||
@ -11,7 +11,7 @@
|
||||
-- See the documentation on the forum for additional information, especially about crafting
|
||||
--
|
||||
--
|
||||
-- For basic development resources, see http://mesecons.net/developers.html
|
||||
-- For developer documentation see the Developers' section on mesecons.TK
|
||||
--
|
||||
--
|
||||
--
|
||||
@ -70,20 +70,26 @@ dofile(minetest.get_modpath("mesecons").."/internal.lua");
|
||||
-- these are the only functions you need to remember
|
||||
|
||||
mesecon.queue:add_function("receptor_on", function (pos, rules)
|
||||
mesecon.vm_begin()
|
||||
|
||||
rules = rules or mesecon.rules.default
|
||||
|
||||
-- Call turnon on all linking positions
|
||||
-- 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 = vector.add(pos, rule)
|
||||
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
|
||||
|
||||
mesecon.vm_commit()
|
||||
end)
|
||||
|
||||
function mesecon.receptor_on(pos, rules)
|
||||
@ -93,21 +99,23 @@ end
|
||||
mesecon.queue:add_function("receptor_off", function (pos, rules)
|
||||
rules = rules or mesecon.rules.default
|
||||
|
||||
-- Call turnoff on all linking positions
|
||||
-- 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 = vector.add(pos, rule)
|
||||
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
|
||||
mesecon.vm_begin()
|
||||
mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
|
||||
|
||||
-- Turnoff returns true if turnoff process was successful, no onstate receptor
|
||||
-- was found along the way. Commit changes that were made in voxelmanip. If turnoff
|
||||
-- returns true, an onstate receptor was found, abort voxelmanip transaction.
|
||||
if (mesecon.turnoff(np, rulename)) then
|
||||
mesecon.vm_commit()
|
||||
if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then
|
||||
mesecon.turnoff(np, rulename)
|
||||
else
|
||||
mesecon.vm_abort()
|
||||
mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -124,5 +132,8 @@ print("[OK] Mesecons")
|
||||
-- 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");
|
||||
|
@ -37,6 +37,11 @@
|
||||
-- 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
|
||||
@ -71,9 +76,7 @@ function mesecon.get_conductor(nodename)
|
||||
end
|
||||
end
|
||||
|
||||
function mesecon.get_any_outputrules(node)
|
||||
if not node then return nil 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
|
||||
@ -81,9 +84,7 @@ function mesecon.get_any_outputrules(node)
|
||||
end
|
||||
end
|
||||
|
||||
function mesecon.get_any_inputrules(node)
|
||||
if not node then return nil 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
|
||||
@ -91,7 +92,7 @@ function mesecon.get_any_inputrules(node)
|
||||
end
|
||||
end
|
||||
|
||||
function mesecon.get_any_rules(node)
|
||||
function mesecon.get_any_rules (node)
|
||||
return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
|
||||
mesecon.get_any_outputrules(node) or {})
|
||||
end
|
||||
@ -181,9 +182,7 @@ end
|
||||
|
||||
-- Activation:
|
||||
mesecon.queue:add_function("activate", function (pos, rulename)
|
||||
local node = mesecon.get_node_force(pos)
|
||||
if not node then return end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
local effector = mesecon.get_effector(node.name)
|
||||
|
||||
if effector and effector.action_on then
|
||||
@ -204,9 +203,7 @@ end
|
||||
|
||||
-- Deactivation
|
||||
mesecon.queue:add_function("deactivate", function (pos, rulename)
|
||||
local node = mesecon.get_node_force(pos)
|
||||
if not node then return end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
local effector = mesecon.get_effector(node.name)
|
||||
|
||||
if effector and effector.action_off then
|
||||
@ -227,9 +224,7 @@ end
|
||||
|
||||
-- Change
|
||||
mesecon.queue:add_function("change", function (pos, rulename, changetype)
|
||||
local node = mesecon.get_node_force(pos)
|
||||
if not node then return end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
local effector = mesecon.get_effector(node.name)
|
||||
|
||||
if effector and effector.action_change then
|
||||
@ -254,8 +249,6 @@ end
|
||||
-- Conductors
|
||||
|
||||
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
|
||||
@ -270,13 +263,10 @@ function mesecon.is_conductor_on(node, rulename)
|
||||
return mesecon.get_bit(binstate, bit)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
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
|
||||
@ -291,7 +281,6 @@ function mesecon.is_conductor_off(node, rulename)
|
||||
return not mesecon.get_bit(binstate, bit)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
@ -351,47 +340,53 @@ end
|
||||
-- some more general high-level stuff
|
||||
|
||||
function mesecon.is_power_on(pos, rulename)
|
||||
local node = mesecon.get_node_force(pos)
|
||||
if node and (mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name)) then
|
||||
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 = mesecon.get_node_force(pos)
|
||||
if node and (mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name)) then
|
||||
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
|
||||
|
||||
-- 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)
|
||||
local node = mesecon.get_node_force(f.pos)
|
||||
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
|
||||
-- Area does not exist; do nothing
|
||||
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)
|
||||
|
||||
-- Call turnon on neighbors
|
||||
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 = vector.add(f.pos, r)
|
||||
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
|
||||
table.insert(frontiers, {pos = np, link = l})
|
||||
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
|
||||
|
||||
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
|
||||
@ -402,81 +397,138 @@ function mesecon.turnon(pos, link)
|
||||
end
|
||||
end
|
||||
|
||||
-- Turn on 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, 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
|
||||
-- }
|
||||
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 signals = {}
|
||||
|
||||
local depth = 1
|
||||
while frontiers[1] do
|
||||
local f = table.remove(frontiers, 1)
|
||||
local node = mesecon.get_node_force(f.pos)
|
||||
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
|
||||
-- Area does not exist; do nothing
|
||||
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)
|
||||
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
|
||||
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:
|
||||
for _, l in ipairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do
|
||||
if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then
|
||||
return false
|
||||
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
|
||||
|
||||
-- Call turnoff on neighbors
|
||||
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
|
||||
table.insert(frontiers, {pos = np, link = l})
|
||||
end
|
||||
end
|
||||
|
||||
mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link))
|
||||
elseif mesecon.is_effector(node.name) then
|
||||
table.insert(signals, {
|
||||
pos = f.pos,
|
||||
node = node,
|
||||
link = f.link,
|
||||
depth = depth
|
||||
})
|
||||
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
|
||||
|
||||
for _, sig in ipairs(signals) do
|
||||
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)
|
||||
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 true
|
||||
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
|
||||
|
||||
-- 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)
|
||||
local inputnode = mesecon.get_node_force(input)
|
||||
local inputrules = mesecon.get_any_inputrules(inputnode)
|
||||
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
|
||||
@ -484,35 +536,37 @@ function mesecon.rules_link_rule_all(output, rule)
|
||||
|
||||
for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
|
||||
-- Check if input accepts from output
|
||||
if vector.equals(vector.add(input, inputrule), output) then
|
||||
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
|
||||
table.insert(rules, inputrule)
|
||||
end
|
||||
end
|
||||
|
||||
return rules
|
||||
end
|
||||
|
||||
-- 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)
|
||||
local outputnode = mesecon.get_node_force(output)
|
||||
local outputrules = mesecon.get_any_outputrules(outputnode)
|
||||
--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 vector.equals(vector.add(output, outputrule), input) then
|
||||
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 = mesecon.get_node_force(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local rules = mesecon.get_any_inputrules(node)
|
||||
if not rules then return false end
|
||||
|
||||
@ -523,11 +577,10 @@ function mesecon.is_powered(pos, rule)
|
||||
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 = vector.add(pos, rname)
|
||||
local nn = mesecon.get_node_force(np)
|
||||
|
||||
if (mesecon.is_conductor_on(nn, mesecon.invertRule(rname))
|
||||
or mesecon.is_receptor_on(nn.name)) then
|
||||
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
|
||||
@ -535,8 +588,8 @@ function mesecon.is_powered(pos, rule)
|
||||
else
|
||||
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
|
||||
for _, rname in ipairs(rulenames) do
|
||||
local np = vector.add(pos, rname)
|
||||
local nn = mesecon.get_node_force(np)
|
||||
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)
|
||||
@ -548,3 +601,52 @@ function mesecon.is_powered(pos, rule)
|
||||
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
|
||||
|
@ -1,14 +1,30 @@
|
||||
-- Un-forceload any forceloaded mapblocks from older versions of Mesecons which
|
||||
-- used forceloading instead of VoxelManipulators.
|
||||
local BLOCKSIZE = 16
|
||||
|
||||
-- convert block hash --> node position
|
||||
local function unhash_blockpos(hash)
|
||||
return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE)
|
||||
-- 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
|
||||
|
||||
local old_forceloaded_blocks = mesecon.file2table("mesecon_forceloaded")
|
||||
for hash, _ in pairs(old_forceloaded_blocks) do
|
||||
minetest.forceload_free_block(unhash_blockpos(hash))
|
||||
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
|
||||
os.remove(minetest.get_worldpath()..DIR_DELIM.."mesecon_forceloaded")
|
||||
|
||||
|
@ -4,7 +4,7 @@ minetest.register_node("mesecons:mesecon_off", {
|
||||
inventory_image = "jeija_mesecon_off.png",
|
||||
wield_image = "jeija_mesecon_off.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
@ -22,7 +22,7 @@ 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 = false,
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
@ -30,7 +30,7 @@ minetest.register_node("mesecons:mesecon_on", {
|
||||
},
|
||||
groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1},
|
||||
drop = "mesecons:mesecon_off 1",
|
||||
light_source = minetest.LIGHT_MAX-11,
|
||||
light_source = LIGHT_MAX-11,
|
||||
mesecons = {conductor={
|
||||
state = mesecon.state.on,
|
||||
offstate = "mesecons:mesecon_off"
|
||||
|
@ -1,85 +1,46 @@
|
||||
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.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.floor = mesecon.mergetable(mesecon.rules.default, {{x = 0, y = -1, z = 0}})
|
||||
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}})
|
||||
|
||||
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.floor, {{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.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},
|
||||
}
|
||||
|
||||
local rules_wallmounted = {
|
||||
xp = mesecon.rotate_rules_down(mesecon.rules.floor),
|
||||
xn = mesecon.rotate_rules_up(mesecon.rules.floor),
|
||||
yp = mesecon.rotate_rules_up(mesecon.rotate_rules_up(mesecon.rules.floor)),
|
||||
yn = mesecon.rules.floor,
|
||||
zp = mesecon.rotate_rules_left(mesecon.rotate_rules_up(mesecon.rules.floor)),
|
||||
zn = mesecon.rotate_rules_right(mesecon.rotate_rules_up(mesecon.rules.floor)),
|
||||
}
|
||||
|
||||
local rules_buttonlike = {
|
||||
xp = mesecon.rules.buttonlike,
|
||||
xn = mesecon.rotate_rules_right(mesecon.rotate_rules_right(mesecon.rules.buttonlike)),
|
||||
yp = mesecon.rotate_rules_down(mesecon.rules.buttonlike),
|
||||
yn = mesecon.rotate_rules_up(mesecon.rules.buttonlike),
|
||||
zp = mesecon.rotate_rules_right(mesecon.rules.buttonlike),
|
||||
zn = mesecon.rotate_rules_left(mesecon.rules.buttonlike),
|
||||
}
|
||||
|
||||
local function rules_from_dir(ruleset, dir)
|
||||
if dir.x == 1 then return ruleset.xp end
|
||||
if dir.y == 1 then return ruleset.yp end
|
||||
if dir.z == 1 then return ruleset.zp end
|
||||
if dir.x == -1 then return ruleset.xn end
|
||||
if dir.y == -1 then return ruleset.yn end
|
||||
if dir.z == -1 then return ruleset.zn end
|
||||
end
|
||||
|
||||
mesecon.rules.wallmounted_get = function(node)
|
||||
local dir = minetest.wallmounted_to_dir(node.param2)
|
||||
return rules_from_dir(rules_wallmounted, dir)
|
||||
end
|
||||
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.buttonlike_get = function(node)
|
||||
local dir = minetest.facedir_to_dir(node.param2)
|
||||
return rules_from_dir(rules_buttonlike, dir)
|
||||
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"
|
||||
|
@ -1,7 +1,7 @@
|
||||
-- Dig and place services
|
||||
|
||||
mesecon.on_placenode = function(pos, node)
|
||||
mesecon.execute_autoconnect_hooks_now(pos, node)
|
||||
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
|
||||
@ -16,26 +16,23 @@ mesecon.on_placenode = function(pos, node)
|
||||
-- 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 = vector.subtract(pos, s)
|
||||
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
|
||||
node.name = mesecon.get_conductor_off(node)
|
||||
minetest.swap_node(pos, node)
|
||||
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
|
||||
if powered then table.insert(powered_rules, r) end
|
||||
|
||||
local state = powered and mesecon.state.on or mesecon.state.off
|
||||
mesecon.changesignal(pos, node, r, state, 1)
|
||||
@ -45,92 +42,53 @@ mesecon.on_placenode = function(pos, node)
|
||||
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)
|
||||
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.execute_autoconnect_hooks_queue(pos, node)
|
||||
mesecon.queue:add_action(pos, "update_autoconnect", {node})
|
||||
end
|
||||
|
||||
function mesecon.on_blastnode(pos, intensity)
|
||||
local node = minetest.get_node(pos)
|
||||
minetest.remove_node(pos)
|
||||
mesecon.on_dignode(pos, node)
|
||||
return minetest.get_node_drops(node.name, "")
|
||||
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
|
||||
local OVERHEAT_MAX = mesecon.setting("overheat_max", 20)
|
||||
local COOLDOWN_TIME = mesecon.setting("cooldown_time", 2.0)
|
||||
local COOLDOWN_STEP = mesecon.setting("cooldown_granularity", 0.5)
|
||||
local COOLDOWN_MULTIPLIER = OVERHEAT_MAX / COOLDOWN_TIME
|
||||
local cooldown_timer = 0.0
|
||||
local object_heat = {}
|
||||
|
||||
-- returns true if heat is too high
|
||||
function mesecon.do_overheat(pos)
|
||||
local id = minetest.hash_node_position(pos)
|
||||
local heat = (object_heat[id] or 0) + 1
|
||||
object_heat[id] = heat
|
||||
if heat >= OVERHEAT_MAX then
|
||||
minetest.log("action", "Node overheats at " .. minetest.pos_to_string(pos))
|
||||
object_heat[id] = nil
|
||||
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
|
||||
|
||||
function mesecon.do_cooldown(pos)
|
||||
local id = minetest.hash_node_position(pos)
|
||||
object_heat[id] = nil
|
||||
end
|
||||
|
||||
function mesecon.get_heat(pos)
|
||||
local id = minetest.hash_node_position(pos)
|
||||
return object_heat[id] or 0
|
||||
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
|
||||
|
||||
function mesecon.move_hot_nodes(moved_nodes)
|
||||
local new_heat = {}
|
||||
for _, n in ipairs(moved_nodes) do
|
||||
local old_id = minetest.hash_node_position(n.oldpos)
|
||||
local new_id = minetest.hash_node_position(n.pos)
|
||||
new_heat[new_id] = object_heat[old_id]
|
||||
object_heat[old_id] = nil
|
||||
end
|
||||
for id, heat in pairs(new_heat) do
|
||||
object_heat[id] = heat
|
||||
end
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local heat = meta:get_int("heat")
|
||||
|
||||
local function global_cooldown(dtime)
|
||||
cooldown_timer = cooldown_timer + dtime
|
||||
if cooldown_timer < COOLDOWN_STEP then
|
||||
return -- don't overload the CPU
|
||||
if (heat > 0) then
|
||||
meta:set_int("heat", heat - 1)
|
||||
end
|
||||
local cooldown = COOLDOWN_MULTIPLIER * cooldown_timer
|
||||
cooldown_timer = 0
|
||||
for id, heat in pairs(object_heat) do
|
||||
heat = heat - cooldown
|
||||
if heat <= 0 then
|
||||
object_heat[id] = nil -- free some RAM
|
||||
else
|
||||
object_heat[id] = heat
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.register_globalstep(global_cooldown)
|
||||
end)
|
||||
|
@ -1,15 +1,10 @@
|
||||
-- SETTINGS
|
||||
function mesecon.setting(setting, default)
|
||||
if type(default) == "boolean" then
|
||||
local read = minetest.settings:get_bool("mesecon."..setting)
|
||||
if read == nil then
|
||||
return default
|
||||
else
|
||||
return read
|
||||
end
|
||||
if type(default) == "bool" then
|
||||
return minetest.setting_getbool("mesecon."..setting) or default
|
||||
elseif type(default) == "string" then
|
||||
return minetest.settings:get("mesecon."..setting) or default
|
||||
return minetest.setting_get("mesecon."..setting) or default
|
||||
elseif type(default) == "number" then
|
||||
return tonumber(minetest.settings:get("mesecon."..setting) or default)
|
||||
return tonumber(minetest.setting_get("mesecon."..setting) or default)
|
||||
end
|
||||
end
|
||||
|
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 487 B |
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 598 B |
Before Width: | Height: | Size: 692 B After Width: | Height: | Size: 692 B |
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 553 B |
Before Width: | Height: | Size: 867 B After Width: | Height: | Size: 867 B |
@ -2,60 +2,10 @@ 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.set_node(newpos, node)
|
||||
minetest.add_node(newpos, node)
|
||||
minetest.get_meta(pos):from_table(meta)
|
||||
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
|
||||
--
|
||||
|
||||
function mesecon.flattenrules(allrules)
|
||||
--[[
|
||||
{
|
||||
@ -100,7 +50,7 @@ function mesecon.rule2bit(findrule, allrules)
|
||||
end
|
||||
for m,metarule in ipairs( allrules) do
|
||||
for _, rule in ipairs(metarule ) do
|
||||
if vector.equals(findrule, rule) then
|
||||
if mesecon.cmpPos(findrule, rule) then
|
||||
return m
|
||||
end
|
||||
end
|
||||
@ -119,7 +69,7 @@ function mesecon.rule2metaindex(findrule, allrules)
|
||||
|
||||
for m, metarule in ipairs( allrules) do
|
||||
for _, rule in ipairs(metarule ) do
|
||||
if vector.equals(findrule, rule) then
|
||||
if mesecon.cmpPos(findrule, rule) then
|
||||
return m
|
||||
end
|
||||
end
|
||||
@ -183,7 +133,15 @@ function mesecon.set_bit(binary,bit,value)
|
||||
end
|
||||
|
||||
function mesecon.invertRule(r)
|
||||
return vector.multiply(r, -1)
|
||||
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
|
||||
@ -228,7 +186,6 @@ end
|
||||
|
||||
function mesecon.register_node(name, spec_common, spec_off, spec_on)
|
||||
spec_common.drop = spec_common.drop or name .. "_off"
|
||||
spec_common.on_blast = spec_common.on_blast or mesecon.on_blastnode
|
||||
spec_common.__mesecon_basename = name
|
||||
spec_on.__mesecon_state = "on"
|
||||
spec_off.__mesecon_state = "off"
|
||||
@ -252,190 +209,3 @@ function mesecon.flipstate(pos, node)
|
||||
|
||||
return newstate
|
||||
end
|
||||
|
||||
-- File writing / reading utilities
|
||||
local wpath = minetest.get_worldpath()
|
||||
function mesecon.file2table(filename)
|
||||
local f = io.open(wpath..DIR_DELIM..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
|
||||
|
||||
function mesecon.table2file(filename, table)
|
||||
local f = io.open(wpath..DIR_DELIM..filename, "w")
|
||||
f:write(minetest.serialize(table))
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- Block position "hashing" (convert to integer) functions for voxelmanip cache
|
||||
local BLOCKSIZE = 16
|
||||
|
||||
-- convert node position --> block hash
|
||||
local function hash_blockpos(pos)
|
||||
return minetest.hash_node_position({
|
||||
x = math.floor(pos.x/BLOCKSIZE),
|
||||
y = math.floor(pos.y/BLOCKSIZE),
|
||||
z = math.floor(pos.z/BLOCKSIZE)
|
||||
})
|
||||
end
|
||||
|
||||
-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
|
||||
-- table.
|
||||
--
|
||||
-- Contents of the table are:
|
||||
-- “vm” → the VoxelManipulator
|
||||
-- “va” → the VoxelArea
|
||||
-- “data” → the data array
|
||||
-- “param1” → the param1 array
|
||||
-- “param2” → the param2 array
|
||||
-- “dirty” → true if data has been modified
|
||||
--
|
||||
-- Nil if no VM-based transaction is in progress.
|
||||
local vm_cache = nil
|
||||
|
||||
-- Starts a VoxelManipulator-based transaction.
|
||||
--
|
||||
-- During a VM transaction, calls to vm_get_node and vm_swap_node operate on a
|
||||
-- cached copy of the world loaded via VoxelManipulators. That cache can later
|
||||
-- be committed to the real map by means of vm_commit or discarded by means of
|
||||
-- vm_abort.
|
||||
function mesecon.vm_begin()
|
||||
vm_cache = {}
|
||||
end
|
||||
|
||||
-- Finishes a VoxelManipulator-based transaction, freeing the VMs and map data
|
||||
-- and writing back any modified areas.
|
||||
function mesecon.vm_commit()
|
||||
for hash, tbl in pairs(vm_cache) do
|
||||
if tbl.dirty then
|
||||
local vm = tbl.vm
|
||||
vm:set_data(tbl.data)
|
||||
vm:write_to_map()
|
||||
vm:update_map()
|
||||
end
|
||||
end
|
||||
vm_cache = nil
|
||||
end
|
||||
|
||||
-- Finishes a VoxelManipulator-based transaction, freeing the VMs and throwing
|
||||
-- away any modified areas.
|
||||
function mesecon.vm_abort()
|
||||
vm_cache = nil
|
||||
end
|
||||
|
||||
-- Gets the cache entry covering a position, populating it if necessary.
|
||||
local function vm_get_or_create_entry(pos)
|
||||
local hash = hash_blockpos(pos)
|
||||
local tbl = vm_cache[hash]
|
||||
if not tbl then
|
||||
local vm = minetest.get_voxel_manip(pos, pos)
|
||||
local min_pos, max_pos = vm:get_emerged_area()
|
||||
local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
|
||||
tbl = {vm = vm, va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data(), dirty = false}
|
||||
vm_cache[hash] = tbl
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
-- Gets the node at a given position during a VoxelManipulator-based
|
||||
-- transaction.
|
||||
function mesecon.vm_get_node(pos)
|
||||
local tbl = vm_get_or_create_entry(pos)
|
||||
local index = tbl.va:indexp(pos)
|
||||
local node_value = tbl.data[index]
|
||||
if node_value == core.CONTENT_IGNORE then
|
||||
return nil
|
||||
else
|
||||
local node_param1 = tbl.param1[index]
|
||||
local node_param2 = tbl.param2[index]
|
||||
return {name = minetest.get_name_from_content_id(node_value), param1 = node_param1, param2 = node_param2}
|
||||
end
|
||||
end
|
||||
|
||||
-- Sets a node’s name during a VoxelManipulator-based transaction.
|
||||
--
|
||||
-- Existing param1, param2, and metadata are left alone.
|
||||
function mesecon.vm_swap_node(pos, name)
|
||||
local tbl = vm_get_or_create_entry(pos)
|
||||
local index = tbl.va:indexp(pos)
|
||||
tbl.data[index] = minetest.get_content_id(name)
|
||||
tbl.dirty = true
|
||||
end
|
||||
|
||||
-- Gets the node at a given position, regardless of whether it is loaded or
|
||||
-- not, respecting a transaction if one is in progress.
|
||||
--
|
||||
-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into
|
||||
-- the server’s main map data cache and then accessed from there.
|
||||
--
|
||||
-- Inside a VM transaction, the transaction’s VM cache is used.
|
||||
function mesecon.get_node_force(pos)
|
||||
if vm_cache then
|
||||
return mesecon.vm_get_node(pos)
|
||||
else
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if node == nil then
|
||||
-- Node is not currently loaded; use a VoxelManipulator to prime
|
||||
-- the mapblock cache and try again.
|
||||
minetest.get_voxel_manip(pos, pos)
|
||||
node = minetest.get_node_or_nil(pos)
|
||||
end
|
||||
return node
|
||||
end
|
||||
end
|
||||
|
||||
-- Swaps the node at a given position, regardless of whether it is loaded or
|
||||
-- not, respecting a transaction if one is in progress.
|
||||
--
|
||||
-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into
|
||||
-- the server’s main map data cache and then accessed from there.
|
||||
--
|
||||
-- Inside a VM transaction, the transaction’s VM cache is used.
|
||||
--
|
||||
-- This function can only be used to change the node’s name, not its parameters
|
||||
-- or metadata.
|
||||
function mesecon.swap_node_force(pos, name)
|
||||
if vm_cache then
|
||||
return mesecon.vm_swap_node(pos, name)
|
||||
else
|
||||
-- This serves to both ensure the mapblock is loaded and also hand us
|
||||
-- the old node table so we can preserve param2.
|
||||
local node = mesecon.get_node_force(pos)
|
||||
node.name = name
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
-- Autoconnect Hooks
|
||||
-- Nodes like conductors may change their appearance and their connection rules
|
||||
-- right after being placed or after being dug, e.g. the default wires use this
|
||||
-- to automatically connect to linking nodes after placement.
|
||||
-- After placement, the update function will be executed immediately so that the
|
||||
-- possibly changed rules can be taken into account when recalculating the circuit.
|
||||
-- After digging, the update function will be queued and executed after
|
||||
-- recalculating the circuit. The update function must take care of updating the
|
||||
-- node at the given position itself, but also all of the other nodes the given
|
||||
-- position may have (had) a linking connection to.
|
||||
mesecon.autoconnect_hooks = {}
|
||||
|
||||
-- name: A unique name for the hook, e.g. "foowire". Used to name the actionqueue function.
|
||||
-- fct: The update function with parameters function(pos, node)
|
||||
function mesecon.register_autoconnect_hook(name, fct)
|
||||
mesecon.autoconnect_hooks[name] = fct
|
||||
mesecon.queue:add_function("autoconnect_hook_"..name, fct)
|
||||
end
|
||||
|
||||
function mesecon.execute_autoconnect_hooks_now(pos, node)
|
||||
for _, fct in pairs(mesecon.autoconnect_hooks) do
|
||||
fct(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
function mesecon.execute_autoconnect_hooks_queue(pos, node)
|
||||
for name in pairs(mesecon.autoconnect_hooks) do
|
||||
mesecon.queue:add_action(pos, "autoconnect_hook_"..name, {node})
|
||||
end
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ local wire_getconnect = function (from_pos, self_pos)
|
||||
end
|
||||
|
||||
for _, r in ipairs(mesecon.flattenrules(rules)) do
|
||||
if (vector.equals(vector.add(self_pos, r), from_pos)) then
|
||||
if (mesecon.cmpPos(mesecon.addPosRule(self_pos, r), from_pos)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
@ -35,7 +35,7 @@ local wire_updateconnect = function (pos)
|
||||
local connections = {}
|
||||
|
||||
for _, r in ipairs(mesecon.rules.default) do
|
||||
if wire_getconnect(pos, vector.add(pos, r)) then
|
||||
if wire_getconnect(pos, mesecon.addPosRule(pos, r)) then
|
||||
table.insert(connections, r)
|
||||
end
|
||||
end
|
||||
@ -83,7 +83,7 @@ local update_on_place_dig = function (pos, node)
|
||||
if (not rules) then return end
|
||||
|
||||
for _, r in ipairs(mesecon.flattenrules(rules)) do
|
||||
local np = vector.add(pos, r)
|
||||
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)
|
||||
@ -91,7 +91,10 @@ local update_on_place_dig = function (pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
mesecon.register_autoconnect_hook("wire", update_on_place_dig)
|
||||
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 ##
|
||||
@ -140,7 +143,7 @@ nid_inc = function (nid)
|
||||
return i <= 8
|
||||
end
|
||||
|
||||
local function register_wires()
|
||||
register_wires = function()
|
||||
local nid = {}
|
||||
while true do
|
||||
-- Create group specifiction and nodeid string (see note above for details)
|
||||
@ -201,22 +204,19 @@ local function register_wires()
|
||||
groups_off["not_in_creative_inventory"] = 1
|
||||
end
|
||||
|
||||
mesecon.register_node(":mesecons:wire_"..nodeid, {
|
||||
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",
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = selectionbox,
|
||||
node_box = nodebox,
|
||||
walkable = false,
|
||||
drop = "mesecons:wire_00000000_off",
|
||||
mesecon_wire = true,
|
||||
sounds = default.node_sound_defaults(),
|
||||
on_rotate = false,
|
||||
mesecon_wire = true
|
||||
}, {tiles = tiles_off, mesecons = meseconspec_off, groups = groups_off},
|
||||
{tiles = tiles_on, mesecons = meseconspec_on, groups = groups_on})
|
||||
|
@ -1,2 +0,0 @@
|
||||
The blinky plants toggles between on and off state every three seconds. Can be used to make clocks. Also works after having restarted the game.
|
||||
It stops blinking in an inactive block, then starts again when the block becomes active.
|
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 2.9 KiB |
@ -24,7 +24,6 @@ mesecon.register_node("mesecons_blinkyplant:blinky_plant", {
|
||||
drawtype = "plantlike",
|
||||
inventory_image = "jeija_blinky_plant_off.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
selection_box = {
|
||||
|
@ -1 +0,0 @@
|
||||
This receptor can be attached to walls. It turns on for 1 second if it's punched.
|
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 7.8 KiB |
@ -4,13 +4,12 @@
|
||||
|
||||
mesecon.button_turnoff = function (pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= "mesecons_button:button_on" then -- has been dug
|
||||
return
|
||||
if node.name=="mesecons_button:button_on" then --has not been dug
|
||||
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2=node.param2})
|
||||
minetest.sound_play("mesecons_button_pop", {pos=pos})
|
||||
local rules = mesecon.rules.buttonlike_get(node)
|
||||
mesecon.receptor_off(pos, rules)
|
||||
end
|
||||
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2})
|
||||
minetest.sound_play("mesecons_button_pop", {pos = pos})
|
||||
local rules = mesecon.rules.buttonlike_get(node)
|
||||
mesecon.receptor_off(pos, rules)
|
||||
end
|
||||
|
||||
minetest.register_node("mesecons_button:button_off", {
|
||||
@ -25,10 +24,8 @@ minetest.register_node("mesecons_button:button_off", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
legacy_wallmounted = true,
|
||||
walkable = false,
|
||||
on_rotate = mesecon.buttonlike_onrotate,
|
||||
sunlight_propagates = true,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
@ -43,18 +40,17 @@ minetest.register_node("mesecons_button:button_off", {
|
||||
},
|
||||
groups = {dig_immediate=2, mesecon_needs_receiver = 1},
|
||||
description = "Button",
|
||||
on_rightclick = function (pos, node)
|
||||
on_punch = function (pos, node)
|
||||
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
|
||||
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
|
||||
minetest.sound_play("mesecons_button_push", {pos=pos})
|
||||
minetest.get_node_timer(pos):start(1)
|
||||
minetest.after(1, mesecon.button_turnoff, pos)
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {receptor = {
|
||||
state = mesecon.state.off,
|
||||
rules = mesecon.rules.buttonlike_get
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_button:button_on", {
|
||||
@ -69,11 +65,9 @@ minetest.register_node("mesecons_button:button_on", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
legacy_wallmounted = true,
|
||||
walkable = false,
|
||||
on_rotate = false,
|
||||
light_source = minetest.LIGHT_MAX-7,
|
||||
light_source = LIGHT_MAX-7,
|
||||
sunlight_propagates = true,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
@ -93,9 +87,7 @@ minetest.register_node("mesecons_button:button_on", {
|
||||
mesecons = {receptor = {
|
||||
state = mesecon.state.on,
|
||||
rules = mesecon.rules.buttonlike_get
|
||||
}},
|
||||
on_timer = mesecon.button_turnoff,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -1,2 +0,0 @@
|
||||
There is no crafting recipe as this should only be available for server admins. Quite similar to the Minecraft counterpart. Executes server commands.
|
||||
It works in inactive blocks.
|
Before Width: | Height: | Size: 36 KiB |
@ -43,7 +43,7 @@ minetest.register_chatcommand("hp", {
|
||||
})
|
||||
|
||||
local function initialize_data(meta)
|
||||
local commands = minetest.formspec_escape(meta:get_string("commands"))
|
||||
local commands = meta:get_string("commands")
|
||||
meta:set_string("formspec",
|
||||
"invsize[9,5;]" ..
|
||||
"textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" ..
|
||||
@ -93,22 +93,9 @@ local function receive_fields(pos, formname, fields, sender)
|
||||
end
|
||||
|
||||
local function resolve_commands(commands, pos)
|
||||
local players = minetest.get_connected_players()
|
||||
|
||||
-- No players online: remove all commands containing
|
||||
-- @nearest, @farthest and @random
|
||||
if #players == 0 then
|
||||
commands = commands:gsub("[^\r\n]+", function (line)
|
||||
if line:find("@nearest") then return "" end
|
||||
if line:find("@farthest") then return "" end
|
||||
if line:find("@random") then return "" end
|
||||
return line
|
||||
end)
|
||||
return commands
|
||||
end
|
||||
|
||||
local nearest, farthest = nil, nil
|
||||
local min_distance, max_distance = math.huge, -1
|
||||
local players = minetest.get_connected_players()
|
||||
for index, player in pairs(players) do
|
||||
local distance = vector.distance(pos, player:getpos())
|
||||
if distance < min_distance then
|
||||
@ -181,7 +168,6 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
|
||||
description = "Command Block",
|
||||
tiles = {"jeija_commandblock_off.png"},
|
||||
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2, mesecon_effector_off=1},
|
||||
on_construct = construct,
|
||||
after_place_node = after_place,
|
||||
@ -190,13 +176,11 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {effector = {
|
||||
action_on = commandblock_action_on
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_commandblock:commandblock_on", {
|
||||
tiles = {"jeija_commandblock_on.png"},
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
|
||||
light_source = 10,
|
||||
drop = "mesecons_commandblock:commandblock_off",
|
||||
@ -207,6 +191,5 @@ minetest.register_node("mesecons_commandblock:commandblock_on", {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {effector = {
|
||||
action_off = commandblock_action_off
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}}
|
||||
})
|
||||
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 323 B |
@ -1 +0,0 @@
|
||||
The delayer delays the signal from the input for a determined time. The time can be set by punching the delayer. Possible delays are: 0.1 seconds, 0.3 seconds, 0.5 seconds and 1 second. You may try to use it for creating songs with the noteblock. It works in unloaded blocks.
|
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 8.3 KiB |
@ -47,8 +47,7 @@ elseif i == 2 then delaytime = 0.3
|
||||
elseif i == 3 then delaytime = 0.5
|
||||
elseif i == 4 then delaytime = 1.0 end
|
||||
|
||||
local boxes = {
|
||||
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
||||
boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
||||
|
||||
{ -2/16, -7/16, -4/16, 2/16, -26/64, -3/16 }, -- the jeweled "on" indicator
|
||||
{ -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 },
|
||||
@ -58,8 +57,7 @@ local boxes = {
|
||||
|
||||
{ -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator
|
||||
{ -8/16, -8/16, -1/16, -6/16, -7/16, 1/16 }, -- the two wire stubs
|
||||
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
|
||||
}
|
||||
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }}
|
||||
|
||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
description = "Delayer",
|
||||
@ -87,7 +85,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
is_ground_content = true,
|
||||
drop = 'mesecons_delayer:delayer_off_1',
|
||||
on_punch = function (pos, node)
|
||||
if node.name=="mesecons_delayer:delayer_off_1" then
|
||||
@ -114,8 +112,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
rules = delayer_get_input_rules,
|
||||
action_on = delayer_activate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -143,7 +140,7 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
is_ground_content = true,
|
||||
drop = 'mesecons_delayer:delayer_off_1',
|
||||
on_punch = function (pos, node)
|
||||
if node.name=="mesecons_delayer:delayer_on_1" then
|
||||
@ -158,7 +155,6 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
end,
|
||||
delayer_time = delaytime,
|
||||
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
receptor =
|
||||
{
|
||||
@ -170,8 +166,7 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
rules = delayer_get_input_rules,
|
||||
action_off = delayer_deactivate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
The node detector is a receptor. It changes its state when either any node
|
||||
or a specific node is detected. Right-click it to set a nodename to scan for.
|
||||
It can also receive digiline signals. You can either send "GET" and it will
|
||||
respond with the detected nodename or you can send any other string and it will
|
||||
set this string as the node to scan for.
|
||||
Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt.
|
||||
The distance parameter specifies how many blocks are between the node detector and the node to detect.
|
||||
Automatic scanning with Mesecons output only works when the detector is in an active block, but Digilines queries always work.
|
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 9.8 KiB |
@ -1,5 +0,0 @@
|
||||
The object detector is a receptor. It changes its state when a player approaches.
|
||||
Right-click it to set a name to scan for.
|
||||
You can also search for comma-separated lists of players where the detector gets activated if any of the names in the list are found.
|
||||
It can also receive digiline signals which are the name to scan for on the specified channel in the right-click menu.
|
||||
Automatic scanning with Mesecons output only works when the detector is in an active block, but Digilines queries always work.
|
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 9.6 KiB |
@ -4,7 +4,7 @@ local GET_COMMAND = "GET"
|
||||
-- Detects players in a certain radius
|
||||
-- The radius can be specified in mesecons/settings.lua
|
||||
|
||||
local function object_detector_make_formspec(pos)
|
||||
local object_detector_make_formspec = function (pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", "size[9,2.5]" ..
|
||||
"field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]"..
|
||||
@ -12,10 +12,8 @@ local function object_detector_make_formspec(pos)
|
||||
"button_exit[7,0.75;2,3;;Save]")
|
||||
end
|
||||
|
||||
local function object_detector_on_receive_fields(pos, formname, fields, sender)
|
||||
if not fields.scanname or not fields.digiline_channel then return end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then return end
|
||||
local object_detector_on_receive_fields = function(pos, formname, fields)
|
||||
if not fields.scanname or not fields.digiline_channel then return end;
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("scanname", fields.scanname)
|
||||
@ -24,38 +22,25 @@ local function object_detector_on_receive_fields(pos, formname, fields, sender)
|
||||
end
|
||||
|
||||
-- returns true if player was found, false if not
|
||||
local function object_detector_scan(pos)
|
||||
local object_detector_scan = function (pos)
|
||||
local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6))
|
||||
|
||||
-- abort if no scan results were found
|
||||
if next(objs) == nil then return false end
|
||||
|
||||
local scanname = minetest.get_meta(pos):get_string("scanname")
|
||||
local scan_for = {}
|
||||
for _, str in pairs(string.split(scanname:gsub(" ", ""), ",")) do
|
||||
scan_for[str] = true
|
||||
end
|
||||
|
||||
local every_player = scanname == ""
|
||||
for _, obj in pairs(objs) do
|
||||
-- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
|
||||
local foundname = obj:get_player_name()
|
||||
if foundname ~= "" then
|
||||
if every_player or scan_for[foundname] then
|
||||
return true
|
||||
end
|
||||
for k, obj in pairs(objs) do
|
||||
local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil!
|
||||
local scanname = minetest.get_meta(pos):get_string("scanname")
|
||||
if (isname == scanname and isname ~= "") or (isname ~= "" and scanname == "") then -- player with scanname found or not scanname specified
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- set player name when receiving a digiline signal on a specific channel
|
||||
local object_detector_digiline = {
|
||||
effector = {
|
||||
action = function(pos, node, channel, msg)
|
||||
action = function (pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if channel == meta:get_string("digiline_channel") then
|
||||
local active_channel = meta:get_string("digiline_channel")
|
||||
if channel == active_channel then
|
||||
meta:set_string("scanname", msg)
|
||||
object_detector_make_formspec(pos)
|
||||
end
|
||||
@ -66,7 +51,6 @@ local object_detector_digiline = {
|
||||
minetest.register_node("mesecons_detector:object_detector_off", {
|
||||
tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = true,
|
||||
groups = {cracky=3},
|
||||
description="Player Detector",
|
||||
@ -77,14 +61,12 @@ minetest.register_node("mesecons_detector:object_detector_off", {
|
||||
on_construct = object_detector_make_formspec,
|
||||
on_receive_fields = object_detector_on_receive_fields,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline = object_detector_digiline,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
digiline = object_detector_digiline
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_detector:object_detector_on", {
|
||||
tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = true,
|
||||
groups = {cracky=3,not_in_creative_inventory=1},
|
||||
drop = 'mesecons_detector:object_detector_off',
|
||||
@ -95,8 +77,7 @@ minetest.register_node("mesecons_detector:object_detector_on", {
|
||||
on_construct = object_detector_make_formspec,
|
||||
on_receive_fields = object_detector_on_receive_fields,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline = object_detector_digiline,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
digiline = object_detector_digiline
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
@ -108,137 +89,85 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'mesecons_detector:object_detector_off',
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"mesecons_detector:object_detector_off"},
|
||||
interval = 1,
|
||||
minetest.register_abm(
|
||||
{nodenames = {"mesecons_detector:object_detector_off"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
if not object_detector_scan(pos) then return end
|
||||
|
||||
node.name = "mesecons_detector:object_detector_on"
|
||||
minetest.swap_node(pos, node)
|
||||
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
||||
action = function(pos)
|
||||
if object_detector_scan(pos) then
|
||||
minetest.swap_node(pos, {name = "mesecons_detector:object_detector_on"})
|
||||
mesecon.receptor_on(pos, mesecon.rules.pplate)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"mesecons_detector:object_detector_on"},
|
||||
interval = 1,
|
||||
minetest.register_abm(
|
||||
{nodenames = {"mesecons_detector:object_detector_on"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
if object_detector_scan(pos) then return end
|
||||
|
||||
node.name = "mesecons_detector:object_detector_off"
|
||||
minetest.swap_node(pos, node)
|
||||
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
||||
action = function(pos)
|
||||
if not object_detector_scan(pos) then
|
||||
minetest.swap_node(pos, {name = "mesecons_detector:object_detector_off"})
|
||||
mesecon.receptor_off(pos, mesecon.rules.pplate)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Node detector
|
||||
-- Detects the node in front of it
|
||||
|
||||
local function node_detector_make_formspec(pos)
|
||||
local node_detector_make_formspec = function (pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("distance") == "" then meta:set_string("distance", "0") end
|
||||
meta:set_string("formspec", "size[9,2.5]" ..
|
||||
"field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]"..
|
||||
"field[0.3,1.5;2.5,2;distance;Distance (0-"..mesecon.setting("node_detector_distance_max", 10).."):;${distance}]"..
|
||||
"field[3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
|
||||
"field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
|
||||
"button_exit[7,0.75;2,3;;Save]")
|
||||
end
|
||||
|
||||
local function node_detector_on_receive_fields(pos, fieldname, fields, sender)
|
||||
if not fields.scanname or not fields.digiline_channel then return end
|
||||
|
||||
if minetest.is_protected(pos, sender:get_player_name()) then return end
|
||||
local node_detector_on_receive_fields = function(pos, formname, fields)
|
||||
if not fields.scanname or not fields.digiline_channel then return end;
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("scanname", fields.scanname)
|
||||
meta:set_string("distance", fields.distance or "0")
|
||||
meta:set_string("digiline_channel", fields.digiline_channel)
|
||||
node_detector_make_formspec(pos)
|
||||
end
|
||||
|
||||
-- returns true if node was found, false if not
|
||||
local function node_detector_scan(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if not node then return end
|
||||
|
||||
-- returns true if player was found, false if not
|
||||
local node_detector_scan = function (pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
||||
local frontnode = minetest.get_node(frontpos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local distance = meta:get_int("distance")
|
||||
local distance_max = mesecon.setting("node_detector_distance_max", 10)
|
||||
if distance < 0 then distance = 0 end
|
||||
if distance > distance_max then distance = distance_max end
|
||||
|
||||
local frontname = minetest.get_node(
|
||||
vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
|
||||
).name
|
||||
local scanname = meta:get_string("scanname")
|
||||
|
||||
return (frontname == scanname) or
|
||||
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
|
||||
return (frontnode.name == meta:get_string("scanname")) or
|
||||
(frontnode.name ~= "air" and frontnode.name ~= "ignore" and meta:get_string("scanname") == "")
|
||||
end
|
||||
|
||||
-- set player name when receiving a digiline signal on a specific channel
|
||||
local node_detector_digiline = {
|
||||
effector = {
|
||||
action = function(pos, node, channel, msg)
|
||||
action = function (pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local distance = meta:get_int("distance")
|
||||
local distance_max = mesecon.setting("node_detector_distance_max", 10)
|
||||
if distance < 0 then distance = 0 end
|
||||
if distance > distance_max then distance = distance_max end
|
||||
|
||||
if channel ~= meta:get_string("digiline_channel") then return end
|
||||
|
||||
if msg == GET_COMMAND then
|
||||
local nodename = minetest.get_node(
|
||||
vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
|
||||
).name
|
||||
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
|
||||
else
|
||||
meta:set_string("scanname", msg)
|
||||
node_detector_make_formspec(pos)
|
||||
local active_channel = meta:get_string("digiline_channel")
|
||||
if channel == active_channel then
|
||||
if msg == GET_COMMAND then
|
||||
local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
||||
local name = minetest.get_node(frontpos).name
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, name)
|
||||
else
|
||||
meta:set_string("scanname", msg)
|
||||
node_detector_make_formspec(pos)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
receptor = {}
|
||||
}
|
||||
|
||||
local function after_place_node_detector(pos, placer)
|
||||
local placer_pos = placer:getpos()
|
||||
if not placer_pos then
|
||||
return
|
||||
end
|
||||
|
||||
--correct for the player's height
|
||||
if placer:is_player() then
|
||||
placer_pos.y = placer_pos.y + 1.625
|
||||
end
|
||||
|
||||
--correct for 6d facedir
|
||||
local node = minetest.get_node(pos)
|
||||
node.param2 = minetest.dir_to_facedir(vector.subtract(pos, placer_pos), true)
|
||||
minetest.set_node(pos, node)
|
||||
end
|
||||
|
||||
minetest.register_node("mesecons_detector:node_detector_off", {
|
||||
tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_off.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = true,
|
||||
groups = {cracky=3},
|
||||
description="Node Detector",
|
||||
@ -247,16 +176,33 @@ minetest.register_node("mesecons_detector:node_detector_off", {
|
||||
}},
|
||||
on_construct = node_detector_make_formspec,
|
||||
on_receive_fields = node_detector_on_receive_fields,
|
||||
after_place_node = function (pos, placer)
|
||||
local placer_pos = placer:getpos()
|
||||
|
||||
--correct for the player's height
|
||||
if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
|
||||
|
||||
--correct for 6d facedir
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
x = pos.x - placer_pos.x,
|
||||
y = pos.y - placer_pos.y,
|
||||
z = pos.z - placer_pos.z
|
||||
}
|
||||
local node = minetest.get_node(pos)
|
||||
node.param2 = minetest.dir_to_facedir(dir, true)
|
||||
minetest.set_node(pos, node)
|
||||
minetest.log("action", "real (6d) facedir: " .. node.param2)
|
||||
end
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline = node_detector_digiline,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
digiline = node_detector_digiline
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_detector:node_detector_on", {
|
||||
tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_on.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = true,
|
||||
groups = {cracky=3,not_in_creative_inventory=1},
|
||||
drop = 'mesecons_detector:node_detector_off',
|
||||
@ -265,9 +211,27 @@ minetest.register_node("mesecons_detector:node_detector_on", {
|
||||
}},
|
||||
on_construct = node_detector_make_formspec,
|
||||
on_receive_fields = node_detector_on_receive_fields,
|
||||
after_place_node = function (pos, placer)
|
||||
local placer_pos = placer:getpos()
|
||||
|
||||
--correct for the player's height
|
||||
if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
|
||||
|
||||
--correct for 6d facedir
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
x = pos.x - placer_pos.x,
|
||||
y = pos.y - placer_pos.y,
|
||||
z = pos.z - placer_pos.z
|
||||
}
|
||||
local node = minetest.get_node(pos)
|
||||
node.param2 = minetest.dir_to_facedir(dir, true)
|
||||
minetest.set_node(pos, node)
|
||||
minetest.log("action", "real (6d) facedir: " .. node.param2)
|
||||
end
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline = node_detector_digiline,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
digiline = node_detector_digiline
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
@ -279,37 +243,26 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'mesecons_detector:node_detector_off',
|
||||
recipe = {
|
||||
{"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"mesecons_detector:node_detector_off"},
|
||||
interval = 1,
|
||||
minetest.register_abm(
|
||||
{nodenames = {"mesecons_detector:node_detector_off"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
if not node_detector_scan(pos) then return end
|
||||
|
||||
node.name = "mesecons_detector:node_detector_on"
|
||||
minetest.swap_node(pos, node)
|
||||
mesecon.receptor_on(pos)
|
||||
if node_detector_scan(pos) then
|
||||
minetest.swap_node(pos, {name = "mesecons_detector:node_detector_on", param2 = node.param2})
|
||||
mesecon.receptor_on(pos)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"mesecons_detector:node_detector_on"},
|
||||
interval = 1,
|
||||
minetest.register_abm(
|
||||
{nodenames = {"mesecons_detector:node_detector_on"},
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
if node_detector_scan(pos) then return end
|
||||
|
||||
node.name = "mesecons_detector:node_detector_off"
|
||||
minetest.swap_node(pos, node)
|
||||
mesecon.receptor_off(pos)
|
||||
if not node_detector_scan(pos) then
|
||||
minetest.swap_node(pos, {name = "mesecons_detector:node_detector_off", param2 = node.param2})
|
||||
mesecon.receptor_off(pos)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
@ -13,60 +13,36 @@ local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
|
||||
minetest.swap_node(pos, {name = replace, param2 = p2})
|
||||
|
||||
if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then
|
||||
minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
else
|
||||
minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
minetest.sound_play("door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
|
||||
end
|
||||
end
|
||||
|
||||
local function meseconify_door(name)
|
||||
if minetest.registered_items[name .. "_b_1"] then
|
||||
-- old style double-node doors
|
||||
local function toggle_state1 (pos, node)
|
||||
on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0})
|
||||
end
|
||||
|
||||
local function toggle_state2 (pos, node)
|
||||
on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2})
|
||||
end
|
||||
|
||||
minetest.override_item(name.."_b_1", {
|
||||
mesecons = {effector = {
|
||||
action_on = toggle_state1,
|
||||
action_off = toggle_state1,
|
||||
rules = mesecon.rules.pplate
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.override_item(name.."_b_2", {
|
||||
mesecons = {effector = {
|
||||
action_on = toggle_state2,
|
||||
action_off = toggle_state2,
|
||||
rules = mesecon.rules.pplate
|
||||
}}
|
||||
})
|
||||
elseif minetest.registered_items[name .. "_a"] then
|
||||
-- new style mesh node based doors
|
||||
local override = {
|
||||
mesecons = {effector = {
|
||||
action_on = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:open()
|
||||
end
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:close()
|
||||
end
|
||||
end,
|
||||
rules = mesecon.rules.pplate
|
||||
}}
|
||||
}
|
||||
minetest.override_item(name .. "_a", override)
|
||||
minetest.override_item(name .. "_b", override)
|
||||
local function toggle_state1 (pos, node)
|
||||
on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0})
|
||||
end
|
||||
|
||||
local function toggle_state2 (pos, node)
|
||||
on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2})
|
||||
end
|
||||
|
||||
minetest.override_item(name.."_b_1", {
|
||||
mesecons = {effector = {
|
||||
action_on = toggle_state1,
|
||||
action_off = toggle_state1,
|
||||
rules = mesecon.rules.pplate
|
||||
}},
|
||||
})
|
||||
|
||||
minetest.override_item(name.."_b_2", {
|
||||
mesecons = {effector = {
|
||||
action_on = toggle_state2,
|
||||
action_off = toggle_state2,
|
||||
rules = mesecon.rules.pplate
|
||||
}},
|
||||
})
|
||||
end
|
||||
|
||||
meseconify_door("doors:door_wood")
|
||||
@ -89,41 +65,16 @@ local function trapdoor_switch(pos, node)
|
||||
minetest.get_meta(pos):set_int("state", state == 1 and 0 or 1)
|
||||
end
|
||||
|
||||
if doors and doors.get then
|
||||
local override = {
|
||||
mesecons = {effector = {
|
||||
action_on = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:open()
|
||||
end
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:close()
|
||||
end
|
||||
end,
|
||||
}},
|
||||
}
|
||||
minetest.override_item("doors:trapdoor", override)
|
||||
minetest.override_item("doors:trapdoor_open", override)
|
||||
minetest.override_item("doors:trapdoor_steel", override)
|
||||
minetest.override_item("doors:trapdoor_steel_open", override)
|
||||
else
|
||||
if minetest.registered_nodes["doors:trapdoor"] then
|
||||
minetest.override_item("doors:trapdoor", {
|
||||
mesecons = {effector = {
|
||||
action_on = trapdoor_switch,
|
||||
action_off = trapdoor_switch
|
||||
}},
|
||||
})
|
||||
minetest.override_item("doors:trapdoor", {
|
||||
mesecons = {effector = {
|
||||
action_on = trapdoor_switch,
|
||||
action_off = trapdoor_switch
|
||||
}},
|
||||
})
|
||||
|
||||
minetest.override_item("doors:trapdoor_open", {
|
||||
mesecons = {effector = {
|
||||
action_on = trapdoor_switch,
|
||||
action_off = trapdoor_switch
|
||||
}},
|
||||
})
|
||||
end
|
||||
end
|
||||
minetest.override_item("doors:trapdoor_open", {
|
||||
mesecons = {effector = {
|
||||
action_on = trapdoor_switch,
|
||||
action_off = trapdoor_switch
|
||||
}},
|
||||
})
|
||||
|
@ -1,15 +1,12 @@
|
||||
local screwdriver_exists = minetest.global_exists("screwdriver")
|
||||
|
||||
local corner_nodebox = {
|
||||
type = "fixed",
|
||||
-- ±0.001 is to prevent z-fighting
|
||||
fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, 3/32}}
|
||||
}
|
||||
|
||||
local corner_selectionbox = {
|
||||
type = "fixed",
|
||||
fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 },
|
||||
fixed = { -16/32-0.001, -18/32, -16/32, 5/32, -12/32, 5/32 },
|
||||
}
|
||||
|
||||
local corner_get_rules = function (node)
|
||||
@ -36,27 +33,23 @@ minetest.register_node("mesecons_extrawires:corner_on", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = corner_selectionbox,
|
||||
node_box = corner_nodebox,
|
||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||
drop = "mesecons_extrawires:corner_off",
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {conductor =
|
||||
{
|
||||
state = mesecon.state.on,
|
||||
rules = corner_get_rules,
|
||||
offstate = "mesecons_extrawires:corner_off"
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:corner_off", {
|
||||
drawtype = "nodebox",
|
||||
description = "Insulated Mesecon Corner",
|
||||
description = "Mesecon Corner",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_curved_tb_off.png",
|
||||
"jeija_insulated_wire_curved_tb_off.png^[transformR270",
|
||||
@ -67,21 +60,17 @@ minetest.register_node("mesecons_extrawires:corner_off", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = corner_selectionbox,
|
||||
node_box = corner_nodebox,
|
||||
groups = {dig_immediate = 3},
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {conductor =
|
||||
{
|
||||
state = mesecon.state.off,
|
||||
rules = corner_get_rules,
|
||||
onstate = "mesecons_extrawires:corner_on"
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -1,4 +1,4 @@
|
||||
local function crossover_get_rules(node)
|
||||
function crossover_get_rules(node)
|
||||
return {
|
||||
{--first wire
|
||||
{x=-1,y=0,z=0},
|
||||
@ -19,110 +19,143 @@ local crossover_states = {
|
||||
}
|
||||
|
||||
minetest.register_node("mesecons_extrawires:crossover_off", {
|
||||
description = "Insulated Mesecon Crossover",
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_crossover.b3d",
|
||||
description = "Insulated Crossover",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_ends_off.png",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_crossing_tb_off.png",
|
||||
"jeija_insulated_wire_crossing_tb_off.png",
|
||||
"jeija_insulated_wire_ends_off.png"
|
||||
},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
stack_max = 99,
|
||||
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||
groups = {dig_immediate=3, mesecon=3},
|
||||
sounds = default.node_sound_defaults(),
|
||||
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
|
||||
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
|
||||
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
|
||||
},
|
||||
},
|
||||
groups = {dig_immediate=3, mesecon=3, mesecon_conductor_craftable=1},
|
||||
mesecons = {
|
||||
conductor = {
|
||||
states = crossover_states,
|
||||
rules = crossover_get_rules(),
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:crossover_01", {
|
||||
description = "You hacker you!",
|
||||
drop = "mesecons_extrawires:crossover_off",
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_crossover.b3d",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_ends_on.png",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_ends_off.png"
|
||||
"jeija_insulated_wire_crossing_tb_01.png",
|
||||
"jeija_insulated_wire_crossing_tb_01.png",
|
||||
"jeija_insulated_wire_ends_01x.png",
|
||||
"jeija_insulated_wire_ends_01x.png",
|
||||
"jeija_insulated_wire_ends_01z.png",
|
||||
"jeija_insulated_wire_ends_01z.png"
|
||||
},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
stack_max = 99,
|
||||
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
|
||||
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
|
||||
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
|
||||
},
|
||||
},
|
||||
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {
|
||||
conductor = {
|
||||
states = crossover_states,
|
||||
rules = crossover_get_rules(),
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:crossover_10", {
|
||||
description = "You hacker you!",
|
||||
drop = "mesecons_extrawires:crossover_off",
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_crossover.b3d",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_ends_off.png",
|
||||
"jeija_insulated_wire_sides_off.png",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_ends_on.png"
|
||||
"jeija_insulated_wire_crossing_tb_10.png",
|
||||
"jeija_insulated_wire_crossing_tb_10.png",
|
||||
"jeija_insulated_wire_ends_10x.png",
|
||||
"jeija_insulated_wire_ends_10x.png",
|
||||
"jeija_insulated_wire_ends_10z.png",
|
||||
"jeija_insulated_wire_ends_10z.png"
|
||||
},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
stack_max = 99,
|
||||
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
|
||||
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
|
||||
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
|
||||
},
|
||||
},
|
||||
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {
|
||||
conductor = {
|
||||
states = crossover_states,
|
||||
rules = crossover_get_rules(),
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:crossover_on", {
|
||||
description = "You hacker you!",
|
||||
drop = "mesecons_extrawires:crossover_off",
|
||||
drawtype = "mesh",
|
||||
mesh = "mesecons_extrawires_crossover.b3d",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_crossing_tb_on.png",
|
||||
"jeija_insulated_wire_crossing_tb_on.png",
|
||||
"jeija_insulated_wire_ends_on.png",
|
||||
"jeija_insulated_wire_ends_on.png",
|
||||
"jeija_insulated_wire_ends_on.png",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_sides_on.png",
|
||||
"jeija_insulated_wire_ends_on.png"
|
||||
},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
stack_max = 99,
|
||||
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
|
||||
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
|
||||
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
|
||||
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
|
||||
},
|
||||
},
|
||||
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {
|
||||
conductor = {
|
||||
states = crossover_states,
|
||||
rules = crossover_get_rules(),
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -1,3 +1,2 @@
|
||||
default
|
||||
mesecons
|
||||
screwdriver?
|
||||
|
@ -1 +0,0 @@
|
||||
Insulated corners are conductors that only conduct between the inputs (also not up or down). When placing they always point to the left in direction of your vision. Like uninsulated wires, they work through unloaded blocks.
|
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 3.8 KiB |
@ -1 +0,0 @@
|
||||
Insulated crossing are conductors that conduct two signals between the opposing sides, the signals are insulated to each other. Like uninsulated wires, they work through unloaded blocks.
|
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 3.7 KiB |
@ -1 +0,0 @@
|
||||
The basic prerequesite for mesecons, can be crafted into wires and other stuff. Have a look at the <a href="http://wiki.minetest.net/Mese">Minetest Wiki</a> for more information. Mese is a conductor. It conducts in all six directions: Up/Down/Left/Right/Forward/Backward. Like horizontal wires, Mese conduction works through unloaded blocks.
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 6.1 KiB |
@ -1 +0,0 @@
|
||||
Insulated T-Junctions are conductors that only conduct between the inputs (also not up or down). Like uninsulated wires, they work through unloaded blocks.
|
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 3.9 KiB |
@ -1 +0,0 @@
|
||||
Vertical Mesecons only conduct up and down. Plates appear at the ends, at that place they also conduct to the side. Like horizontal wires, they work through unloaded blocks.
|
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.0 KiB |
@ -16,22 +16,15 @@ minetest.override_item("default:mese", {
|
||||
}}
|
||||
})
|
||||
|
||||
-- Copy node definition of powered mese from normal mese
|
||||
-- and brighten texture tiles to indicate mese is powered
|
||||
local powered_def = mesecon.mergetable(minetest.registered_nodes["default:mese"], {
|
||||
drop = "default:mese",
|
||||
light_source = 5,
|
||||
minetest.register_node("mesecons_extrawires:mese_powered", {
|
||||
tiles = {minetest.registered_nodes["default:mese"].tiles[1].."^[brighten"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=1, not_in_creative_inventory = 1},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
offstate = "default:mese",
|
||||
rules = mesewire_rules
|
||||
}},
|
||||
groups = {cracky = 1, not_in_creative_inventory = 1},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
drop = "default:mese"
|
||||
})
|
||||
|
||||
for i, v in pairs(powered_def.tiles) do
|
||||
powered_def.tiles[i] = v .. "^[brighten"
|
||||
end
|
||||
|
||||
minetest.register_node("mesecons_extrawires:mese_powered", powered_def)
|
||||
|
@ -1,15 +1,12 @@
|
||||
local screwdriver_exists = minetest.global_exists("screwdriver")
|
||||
|
||||
local tjunction_nodebox = {
|
||||
type = "fixed",
|
||||
-- ±0.001 is to prevent z-fighting
|
||||
fixed = {{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
|
||||
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, -3/32},}
|
||||
}
|
||||
|
||||
local tjunction_selectionbox = {
|
||||
type = "fixed",
|
||||
fixed = { -16/32, -16/32, -16/32, 16/32, -12/32, 7/32 },
|
||||
fixed = { -16/32-0.001, -18/32, -16/32, 16/32+0.001, -12/32, 7/32 },
|
||||
}
|
||||
|
||||
local tjunction_get_rules = function (node)
|
||||
@ -37,27 +34,23 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = tjunction_selectionbox,
|
||||
node_box = tjunction_nodebox,
|
||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||
drop = "mesecons_extrawires:tjunction_off",
|
||||
sounds = default.node_sound_defaults(),
|
||||
mesecons = {conductor =
|
||||
{
|
||||
state = mesecon.state.on,
|
||||
rules = tjunction_get_rules,
|
||||
offstate = "mesecons_extrawires:tjunction_off"
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_node("mesecons_extrawires:tjunction_off", {
|
||||
drawtype = "nodebox",
|
||||
description = "Insulated Mesecon T-junction",
|
||||
description = "T-junction",
|
||||
tiles = {
|
||||
"jeija_insulated_wire_tjunction_tb_off.png",
|
||||
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180",
|
||||
@ -68,21 +61,17 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = tjunction_selectionbox,
|
||||
node_box = tjunction_nodebox,
|
||||
groups = {dig_immediate = 3},
|
||||
sounds = default.node_sound_defaults(),
|
||||
groups = {dig_immediate = 3, mesecon_conductor_craftable=1},
|
||||
mesecons = {conductor =
|
||||
{
|
||||
state = mesecon.state.off,
|
||||
rules = tjunction_get_rules,
|
||||
onstate = "mesecons_extrawires:tjunction_on"
|
||||
}},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||
}}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
|
@ -42,57 +42,52 @@ local vertical_updatepos = function (pos)
|
||||
local node = minetest.get_node(pos)
|
||||
if minetest.registered_nodes[node.name]
|
||||
and minetest.registered_nodes[node.name].is_vertical_conductor then
|
||||
local node_above = minetest.get_node(vector.add(pos, vertical_rules[1]))
|
||||
local node_below = minetest.get_node(vector.add(pos, vertical_rules[2]))
|
||||
local node_above = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[1]))
|
||||
local node_below = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[2]))
|
||||
local namestate = minetest.registered_nodes[node.name].vertical_conductor_state
|
||||
|
||||
local above = minetest.registered_nodes[node_above.name]
|
||||
and minetest.registered_nodes[node_above.name].is_vertical_conductor
|
||||
local below = minetest.registered_nodes[node_below.name]
|
||||
and minetest.registered_nodes[node_below.name].is_vertical_conductor
|
||||
|
||||
mesecon.on_dignode(pos, node)
|
||||
|
||||
-- Always place offstate conductor and let mesecon.on_placenode take care
|
||||
local newname = "mesecons_extrawires:vertical_"
|
||||
local basename = "mesecons_extrawires:vertical_"
|
||||
if above and below then -- above and below: vertical mesecon
|
||||
newname = newname .. "off"
|
||||
minetest.add_node(pos, {name = basename .. namestate})
|
||||
elseif above and not below then -- above only: bottom
|
||||
newname = newname .. "bottom_off"
|
||||
minetest.add_node(pos, {name = basename .. "bottom_" .. namestate})
|
||||
elseif not above and below then -- below only: top
|
||||
newname = newname .. "top_off"
|
||||
minetest.add_node(pos, {name = basename .. "top_" .. namestate})
|
||||
else -- no vertical wire above, no vertical wire below: use bottom
|
||||
newname = newname .. "bottom_off"
|
||||
minetest.add_node(pos, {name = basename .. "bottom_" .. namestate})
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name = newname})
|
||||
mesecon.on_placenode(pos, {name = newname})
|
||||
mesecon.update_autoconnect(pos)
|
||||
end
|
||||
end
|
||||
|
||||
local vertical_update = function (pos, node)
|
||||
vertical_updatepos(pos) -- this one
|
||||
vertical_updatepos(vector.add(pos, vertical_rules[1])) -- above
|
||||
vertical_updatepos(vector.add(pos, vertical_rules[2])) -- below
|
||||
vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[1])) -- above
|
||||
vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[2])) -- below
|
||||
end
|
||||
|
||||
-- Vertical wire
|
||||
mesecon.register_node("mesecons_extrawires:vertical", {
|
||||
description = "Vertical Mesecon",
|
||||
description = "Vertical mesecon",
|
||||
drawtype = "nodebox",
|
||||
walkable = false,
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
selection_box = vertical_box,
|
||||
node_box = vertical_box,
|
||||
is_vertical_conductor = true,
|
||||
drop = "mesecons_extrawires:vertical_off",
|
||||
after_place_node = vertical_update,
|
||||
after_dig_node = vertical_update,
|
||||
sounds = default.node_sound_defaults(),
|
||||
after_dig_node = vertical_update
|
||||
},{
|
||||
tiles = {"mesecons_wire_off.png"},
|
||||
groups = {dig_immediate=3},
|
||||
vertical_conductor_state = "off",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.off,
|
||||
onstate = "mesecons_extrawires:vertical_on",
|
||||
@ -101,6 +96,7 @@ mesecon.register_node("mesecons_extrawires:vertical", {
|
||||
},{
|
||||
tiles = {"mesecons_wire_on.png"},
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1},
|
||||
vertical_conductor_state = "on",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
offstate = "mesecons_extrawires:vertical_off",
|
||||
@ -114,7 +110,6 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
|
||||
drawtype = "nodebox",
|
||||
walkable = false,
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
groups = {dig_immediate=3, not_in_creative_inventory=1},
|
||||
selection_box = top_box,
|
||||
@ -122,10 +117,10 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
|
||||
is_vertical_conductor = true,
|
||||
drop = "mesecons_extrawires:vertical_off",
|
||||
after_place_node = vertical_update,
|
||||
after_dig_node = vertical_update,
|
||||
sounds = default.node_sound_defaults(),
|
||||
after_dig_node = vertical_update
|
||||
},{
|
||||
tiles = {"mesecons_wire_off.png"},
|
||||
vertical_conductor_state = "off",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.off,
|
||||
onstate = "mesecons_extrawires:vertical_top_on",
|
||||
@ -133,6 +128,7 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
|
||||
}}
|
||||
},{
|
||||
tiles = {"mesecons_wire_on.png"},
|
||||
vertical_conductor_state = "on",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
offstate = "mesecons_extrawires:vertical_top_off",
|
||||
@ -146,7 +142,6 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
|
||||
drawtype = "nodebox",
|
||||
walkable = false,
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||
selection_box = bottom_box,
|
||||
@ -154,10 +149,10 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
|
||||
is_vertical_conductor = true,
|
||||
drop = "mesecons_extrawires:vertical_off",
|
||||
after_place_node = vertical_update,
|
||||
after_dig_node = vertical_update,
|
||||
sounds = default.node_sound_defaults(),
|
||||
after_dig_node = vertical_update
|
||||
},{
|
||||
tiles = {"mesecons_wire_off.png"},
|
||||
vertical_conductor_state = "off",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.off,
|
||||
onstate = "mesecons_extrawires:vertical_bottom_on",
|
||||
@ -165,6 +160,7 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
|
||||
}}
|
||||
},{
|
||||
tiles = {"mesecons_wire_on.png"},
|
||||
vertical_conductor_state = "on",
|
||||
mesecons = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
offstate = "mesecons_extrawires:vertical_bottom_off",
|
||||
|
@ -1,2 +0,0 @@
|
||||
mesecons
|
||||
screwdriver?
|
@ -1,6 +0,0 @@
|
||||
FPGAs can be used to chain multiple logic gates together in a compact manner.
|
||||
They come with 4 I/O ports and 10 internal registers,
|
||||
which can then be connected with each other to form logic circuits.
|
||||
They work fine in unloaded blocks.<br />
|
||||
Supported gate types: <b>AND</b>, <b>OR</b>, <b>NOT</b>, <b>XOR</b>, <b>NAND</b>, <b>XNOR</b>, <b>Buffer</b> (=)<br />
|
||||
I/O ports: <b>A B C D</b>; Registers: numbered <b>0</b> to <b>9</b>
|
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 3.1 KiB |
@ -1,3 +0,0 @@
|
||||
The FPGA programmer can be used to copy gate configurations from one FPGA to another.<br />
|
||||
Shift+Right-Click an FPGA to read its configuration and "remember" it.
|
||||
Left-click (punch) FPGAs to write the saved configuration to them.
|
Before Width: | Height: | Size: 598 B |
Before Width: | Height: | Size: 1.9 KiB |
@ -1,420 +0,0 @@
|
||||
local plg = {}
|
||||
plg.rules = {}
|
||||
|
||||
local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua")
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg)
|
||||
|
||||
|
||||
plg.register_nodes = function(template)
|
||||
-- each loop is for one of the 4 IO ports
|
||||
for a = 0, 1 do
|
||||
for b = 0, 1 do
|
||||
for c = 0, 1 do
|
||||
for d = 0, 1 do
|
||||
local ndef = table.copy(template)
|
||||
local nodename = "mesecons_fpga:fpga"
|
||||
.. tostring(d) .. tostring(c) .. tostring(b) .. tostring(a)
|
||||
|
||||
-- build top texture string
|
||||
local texture = "jeija_fpga_top.png"
|
||||
if a == 1 then texture = texture .. "^jeija_microcontroller_LED_A.png" end
|
||||
if b == 1 then texture = texture .. "^jeija_microcontroller_LED_B.png" end
|
||||
if c == 1 then texture = texture .. "^jeija_microcontroller_LED_C.png" end
|
||||
if d == 1 then texture = texture .. "^jeija_microcontroller_LED_D.png" end
|
||||
ndef.tiles[1] = texture
|
||||
ndef.inventory_image = texture
|
||||
|
||||
if (a + b + c + d) > 0 then
|
||||
ndef.groups["not_in_creative_inventory"] = 1
|
||||
end
|
||||
|
||||
-- interaction with mesecons (input / output)
|
||||
local rules_out = {}
|
||||
if a == 1 then table.insert(rules_out, {x = -1, y = 0, z = 0}) end
|
||||
if b == 1 then table.insert(rules_out, {x = 0, y = 0, z = 1}) end
|
||||
if c == 1 then table.insert(rules_out, {x = 1, y = 0, z = 0}) end
|
||||
if d == 1 then table.insert(rules_out, {x = 0, y = 0, z = -1}) end
|
||||
plg.rules[nodename] = rules_out
|
||||
|
||||
local rules_in = {}
|
||||
if a == 0 then table.insert(rules_in, {x = -1, y = 0, z = 0}) end
|
||||
if b == 0 then table.insert(rules_in, {x = 0, y = 0, z = 1}) end
|
||||
if c == 0 then table.insert(rules_in, {x = 1, y = 0, z = 0}) end
|
||||
if d == 0 then table.insert(rules_in, {x = 0, y = 0, z = -1}) end
|
||||
ndef.mesecons.effector.rules = rules_in
|
||||
|
||||
if (a + b + c + d) > 0 then
|
||||
ndef.mesecons.receptor = {
|
||||
state = mesecon.state.on,
|
||||
rules = rules_out,
|
||||
}
|
||||
end
|
||||
|
||||
minetest.register_node(nodename, ndef)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
plg.register_nodes({
|
||||
description = "FPGA",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"", -- replaced later
|
||||
"jeija_microcontroller_bottom.png",
|
||||
"jeija_fpga_sides.png",
|
||||
"jeija_fpga_sides.png",
|
||||
"jeija_fpga_sides.png",
|
||||
"jeija_fpga_sides.png"
|
||||
},
|
||||
inventory_image = "", -- replaced later
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
paramtype = "light",
|
||||
walkable = true,
|
||||
groups = {dig_immediate = 2, mesecon = 3, overheat = 1},
|
||||
drop = "mesecons_fpga:fpga0000",
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
|
||||
{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board
|
||||
{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC
|
||||
}
|
||||
},
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local is = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} }
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
meta:set_int("valid", 0)
|
||||
meta:set_string("formspec", plg.to_formspec_string(is))
|
||||
meta:set_string("infotext", "FPGA")
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
if fields.program == nil then return end -- we only care when the user clicks "Program"
|
||||
local meta = minetest.get_meta(pos)
|
||||
local is = plg.from_formspec_fields(fields)
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
plg.update_formspec(pos, is)
|
||||
end,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
effector = {
|
||||
rules = {}, -- replaced later
|
||||
action_change = function(pos, node, rule, newstate)
|
||||
plg.ports_changed(pos, rule, newstate)
|
||||
plg.update(pos)
|
||||
end
|
||||
}
|
||||
},
|
||||
after_dig_node = function(pos, node)
|
||||
mesecon.receptor_off(pos, plg.rules[node.name])
|
||||
end,
|
||||
on_blast = mesecon.on_blastnode,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
local abcd1 = {"A", "B", "C", "D"}
|
||||
local abcd2 = {A = 1, B = 2, C = 3, D = 4}
|
||||
local ops = {"op1", "op2", "dst"}
|
||||
local dir = 0
|
||||
if mode == screwdriver.ROTATE_FACE then -- clock-wise
|
||||
dir = 1
|
||||
if user and user:is_player() then
|
||||
minetest.chat_send_player(user:get_player_name(),
|
||||
"FPGA ports have been rotated clockwise.")
|
||||
end
|
||||
elseif mode == screwdriver.ROTATE_AXIS then -- counter-clockwise
|
||||
dir = -1
|
||||
if user and user:is_player() then
|
||||
minetest.chat_send_player(user:get_player_name(),
|
||||
"FPGA ports have been rotated counter-clockwise.")
|
||||
end
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local instr = lcore.deserialize(meta:get_string("instr"))
|
||||
for i = 1, #instr do
|
||||
for _, op in ipairs(ops) do
|
||||
local o = instr[i][op]
|
||||
if o and o.type == "io" then
|
||||
local num = abcd2[o.port]
|
||||
num = num + dir
|
||||
if num > 4 then num = 1
|
||||
elseif num < 1 then num = 4 end
|
||||
instr[i][op].port = abcd1[num]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
meta:set_string("instr", lcore.serialize(instr))
|
||||
plg.update_formspec(pos, instr)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
plg.to_formspec_string = function(is)
|
||||
local function dropdown_op(x, y, name, val)
|
||||
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
|
||||
.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored?
|
||||
s = s .. " ,A,B,C,D,0,1,2,3,4,5,6,7,8,9;"
|
||||
if val == nil then
|
||||
s = s .. "0" -- actually selects no field at all
|
||||
elseif val.type == "io" then
|
||||
local mapping = {
|
||||
["A"] = 1,
|
||||
["B"] = 2,
|
||||
["C"] = 3,
|
||||
["D"] = 4,
|
||||
}
|
||||
s = s .. tostring(1 + mapping[val.port])
|
||||
else -- "reg"
|
||||
s = s .. tostring(6 + val.n)
|
||||
end
|
||||
return s .. "]"
|
||||
end
|
||||
local function dropdown_action(x, y, name, val)
|
||||
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
|
||||
.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored?
|
||||
s = s .. " , AND, OR, NOT, XOR,NAND, =,XNOR;"
|
||||
if val == nil then
|
||||
return s .. "0]" -- actually selects no field at all
|
||||
end
|
||||
local mapping = {
|
||||
["and"] = 1,
|
||||
["or"] = 2,
|
||||
["not"] = 3,
|
||||
["xor"] = 4,
|
||||
["nand"] = 5,
|
||||
["buf"] = 6,
|
||||
["xnor"] = 7,
|
||||
}
|
||||
return s .. tostring(1 + mapping[val]) .. "]"
|
||||
end
|
||||
local s = "size[9,9]"..
|
||||
"label[3.4,-0.15;FPGA gate configuration]"..
|
||||
"button_exit[7,7.5;2,2.5;program;Program]"..
|
||||
"box[4.2,0.5;0.03,7;#ffffff]"..
|
||||
"label[0.25,0.25;op. 1]"..
|
||||
"label[1.0,0.25;gate type]"..
|
||||
"label[2.125,0.25;op. 2]"..
|
||||
"label[3.15,0.25;dest]"..
|
||||
"label[4.5,0.25;op. 1]"..
|
||||
"label[5.25,0.25;gate type]"..
|
||||
"label[6.375,0.25;op. 2]"..
|
||||
"label[7.4,0.25;dest]"
|
||||
local x = 1 - 0.75
|
||||
local y = 1 - 0.25
|
||||
for i = 1, 14 do
|
||||
local cur = is[i]
|
||||
s = s .. dropdown_op (x , y, tostring(i).."op1", cur.op1)
|
||||
s = s .. dropdown_action(x+0.75 , y, tostring(i).."act", cur.action)
|
||||
s = s .. dropdown_op (x+1.875, y, tostring(i).."op2", cur.op2)
|
||||
s = s .. "label[" .. tostring(x+2.625) .. "," .. tostring(y+0.1) .. "; ->]"
|
||||
s = s .. dropdown_op (x+2.9 , y, tostring(i).."dst", cur.dst)
|
||||
y = y + 1
|
||||
|
||||
if i == 7 then
|
||||
x = 4.5
|
||||
y = 1 - 0.25
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
plg.from_formspec_fields = function(fields)
|
||||
local function read_op(s)
|
||||
if s == nil or s == " " then
|
||||
return nil
|
||||
elseif s == "A" or s == "B" or s == "C" or s == "D" then
|
||||
return {type = "io", port = s}
|
||||
else
|
||||
return {type = "reg", n = tonumber(s)}
|
||||
end
|
||||
end
|
||||
local function read_action(s)
|
||||
if s == nil or s == " " then
|
||||
return nil
|
||||
end
|
||||
local mapping = {
|
||||
["AND"] = "and",
|
||||
["OR"] = "or",
|
||||
["NOT"] = "not",
|
||||
["XOR"] = "xor",
|
||||
["NAND"] = "nand",
|
||||
["="] = "buf",
|
||||
["XNOR"] = "xnor",
|
||||
}
|
||||
s = s:gsub("^%s*", "") -- remove leading spaces
|
||||
return mapping[s]
|
||||
end
|
||||
local is = {}
|
||||
for i = 1, 14 do
|
||||
local cur = {}
|
||||
cur.op1 = read_op(fields[tonumber(i) .. "op1"])
|
||||
cur.action = read_action(fields[tonumber(i) .. "act"])
|
||||
cur.op2 = read_op(fields[tonumber(i) .. "op2"])
|
||||
cur.dst = read_op(fields[tonumber(i) .. "dst"])
|
||||
is[#is + 1] = cur
|
||||
end
|
||||
return is
|
||||
end
|
||||
|
||||
plg.update_formspec = function(pos, is)
|
||||
if type(is) == "string" then -- serialized string
|
||||
is = lcore.deserialize(is)
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local form = plg.to_formspec_string(is)
|
||||
|
||||
local err = lcore.validate(is)
|
||||
if err == nil then
|
||||
meta:set_int("valid", 1)
|
||||
meta:set_string("infotext", "FPGA (functional)")
|
||||
else
|
||||
meta:set_int("valid", 0)
|
||||
meta:set_string("infotext", "FPGA")
|
||||
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
|
||||
form = form .. plg.red_box_around(err.i) ..
|
||||
"label[0.25,8.25;The gate configuration is erroneous in the marked area:]"..
|
||||
"label[0.25,8.5;" .. fmsg .. "]"
|
||||
end
|
||||
|
||||
meta:set_string("formspec", form)
|
||||
|
||||
-- reset ports and run programmed logic
|
||||
plg.setports(pos, false, false, false, false)
|
||||
plg.update(pos)
|
||||
end
|
||||
|
||||
plg.red_box_around = function(i)
|
||||
local x, y
|
||||
if i > 7 then
|
||||
x = 4.5
|
||||
y = 0.75 + (i - 8)
|
||||
else
|
||||
x = 0.25
|
||||
y = 0.75 + (i - 1)
|
||||
end
|
||||
return string.format("box[%f,%f;3.8,0.8;#ff0000]", x-0.1, y-0.05)
|
||||
end
|
||||
|
||||
|
||||
plg.update = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_int("valid") ~= 1 then
|
||||
return
|
||||
elseif mesecon.do_overheat(pos) then
|
||||
plg.setports(pos, false, false, false, false)
|
||||
meta:set_int("valid", 0)
|
||||
meta:set_string("infotext", "FPGA (overheated)")
|
||||
return
|
||||
end
|
||||
|
||||
local is = lcore.deserialize(meta:get_string("instr"))
|
||||
local A, B, C, D = plg.getports(pos)
|
||||
A, B, C, D = lcore.interpret(is, A, B, C, D)
|
||||
plg.setports(pos, A, B, C, D)
|
||||
end
|
||||
|
||||
plg.ports_changed = function(pos, rule, newstate)
|
||||
if rule == nil then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local states
|
||||
|
||||
local s = meta:get_string("portstates")
|
||||
if s == nil then
|
||||
states = {false, false, false, false}
|
||||
else
|
||||
states = {
|
||||
s:sub(1, 1) == "1",
|
||||
s:sub(2, 2) == "1",
|
||||
s:sub(3, 3) == "1",
|
||||
s:sub(4, 4) == "1",
|
||||
}
|
||||
end
|
||||
|
||||
-- trick to transform rules (see register_node) into port number
|
||||
local portno = ({4, 1, nil, 3, 2})[3 + rule.x + 2*rule.z]
|
||||
states[portno] = (newstate == "on")
|
||||
|
||||
meta:set_string("portstates",
|
||||
(states[1] and "1" or "0") .. (states[2] and "1" or "0") ..
|
||||
(states[3] and "1" or "0") .. (states[4] and "1" or "0")
|
||||
)
|
||||
end
|
||||
|
||||
plg.getports = function(pos) -- gets merged states of INPUT & OUTPUT
|
||||
local sin, sout
|
||||
|
||||
local s = minetest.get_meta(pos):get_string("portstates")
|
||||
if s == nil then
|
||||
sin = {false, false, false, false}
|
||||
else
|
||||
sin = {
|
||||
s:sub(1, 1) == "1",
|
||||
s:sub(2, 2) == "1",
|
||||
s:sub(3, 3) == "1",
|
||||
s:sub(4, 4) == "1",
|
||||
}
|
||||
end
|
||||
|
||||
local name = minetest.get_node(pos).name
|
||||
assert(name:find("mesecons_fpga:fpga") == 1)
|
||||
local off = #"mesecons_fpga:fpga"
|
||||
sout = {
|
||||
name:sub(off+4, off+4) == "1",
|
||||
name:sub(off+3, off+3) == "1",
|
||||
name:sub(off+2, off+2) == "1",
|
||||
name:sub(off+1, off+1) == "1",
|
||||
}
|
||||
|
||||
return unpack({
|
||||
sin[1] or sout[1],
|
||||
sin[2] or sout[2],
|
||||
sin[3] or sout[3],
|
||||
sin[4] or sout[4],
|
||||
})
|
||||
end
|
||||
|
||||
plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
|
||||
local base = "mesecons_fpga:fpga"
|
||||
|
||||
local name = base
|
||||
.. (D and "1" or "0") .. (C and "1" or "0")
|
||||
.. (B and "1" or "0") .. (A and "1" or "0")
|
||||
minetest.swap_node(pos, {name = name, param2 = minetest.get_node(pos).param2})
|
||||
|
||||
if A ~= nil then
|
||||
local ru = plg.rules[base .. "0001"]
|
||||
if A then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
|
||||
end
|
||||
if B ~= nil then
|
||||
local ru = plg.rules[base .. "0010"]
|
||||
if B then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
|
||||
end
|
||||
if C ~= nil then
|
||||
local ru = plg.rules[base .. "0100"]
|
||||
if C then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
|
||||
end
|
||||
if D ~= nil then
|
||||
local ru = plg.rules[base .. "1000"]
|
||||
if D then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mesecons_fpga:fpga0000 2",
|
||||
recipe = {
|
||||
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'},
|
||||
{'mesecons_materials:silicon', 'mesecons_materials:silicon'},
|
||||
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'},
|
||||
}
|
||||
})
|
@ -1,210 +0,0 @@
|
||||
local lg = {}
|
||||
|
||||
-- (de)serialize
|
||||
lg.serialize = function(t)
|
||||
local function _op(t)
|
||||
if t == nil then
|
||||
return " "
|
||||
elseif t.type == "io" then
|
||||
return t.port
|
||||
else -- t.type == "reg"
|
||||
return tostring(t.n)
|
||||
end
|
||||
end
|
||||
local function _action(s)
|
||||
if s == nil then
|
||||
return " "
|
||||
end
|
||||
local mapping = {
|
||||
["and"] = "&",
|
||||
["or"] = "|",
|
||||
["not"] = "~",
|
||||
["xor"] = "^",
|
||||
["nand"] = "?", --dunno
|
||||
["buf"] = "_",
|
||||
["xnor"] = "=",
|
||||
}
|
||||
return mapping[s]
|
||||
end
|
||||
|
||||
local s = ""
|
||||
for i = 1, 14 do
|
||||
local cur = t[i]
|
||||
if next(cur) ~= nil then
|
||||
s = s .. _op(cur.op1) .. _action(cur.action) .. _op(cur.op2) .. _op(cur.dst)
|
||||
end
|
||||
s = s .. "/"
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
lg.deserialize = function(s)
|
||||
local function _op(c)
|
||||
if c == "A" or c == "B" or c == "C" or c == "D" then
|
||||
return {type = "io", port = c}
|
||||
elseif c == " " then
|
||||
return nil
|
||||
else
|
||||
return {type = "reg", n = tonumber(c)}
|
||||
end
|
||||
end
|
||||
local function _action(c)
|
||||
local mapping = {
|
||||
["&"] = "and",
|
||||
["|"] = "or",
|
||||
["~"] = "not",
|
||||
["^"] = "xor",
|
||||
["?"] = "nand",
|
||||
["_"] = "buf",
|
||||
["="] = "xnor",
|
||||
[" "] = nil,
|
||||
}
|
||||
return mapping[c]
|
||||
end
|
||||
|
||||
local ret = {}
|
||||
for part in s:gmatch("(.-)/") do
|
||||
local parsed
|
||||
if part == "" then
|
||||
parsed = {}
|
||||
else
|
||||
parsed = {
|
||||
action = _action( part:sub(2,2) ),
|
||||
op1 = _op( part:sub(1,1) ),
|
||||
op2 = _op( part:sub(3,3) ),
|
||||
dst = _op( part:sub(4,4) ),
|
||||
}
|
||||
end
|
||||
ret[#ret + 1] = parsed
|
||||
end
|
||||
-- More than 14 instructions (write to all 10 regs + 4 outputs)
|
||||
-- will not pass the write-once requirement of the validator
|
||||
assert(#ret == 14)
|
||||
return ret
|
||||
end
|
||||
|
||||
-- validation
|
||||
lg.validate_single = function(t, i)
|
||||
local function is_reg_written_to(t, n, max)
|
||||
for i = 1, max-1 do
|
||||
if next(t[i]) ~= nil
|
||||
and t[i].dst and t[i].dst.type == "reg"
|
||||
and t[i].dst.n == n then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function compare_op(t1, t2, allow_same_io)
|
||||
if t1 == nil or t2 == nil then
|
||||
return false
|
||||
elseif t1.type ~= t2.type then
|
||||
return false
|
||||
end
|
||||
if t1.type == "reg" and t1.n == t2.n then
|
||||
return true
|
||||
elseif t1.type == "io" and t1.port == t2.port then
|
||||
return not allow_same_io
|
||||
end
|
||||
return false
|
||||
end
|
||||
local elem = t[i]
|
||||
-- check for completeness
|
||||
if elem.action == nil then
|
||||
return {i = i, msg = "Gate type required"}
|
||||
elseif elem.action == "not" or elem.action == "buf" then
|
||||
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then
|
||||
return {i = i, msg = "Second operand (only) and destination required"}
|
||||
end
|
||||
else
|
||||
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
|
||||
return {i = i, msg = "Operands and destination required"}
|
||||
end
|
||||
end
|
||||
-- check whether operands/destination are identical
|
||||
if compare_op(elem.op1, elem.op2) then
|
||||
return {i = i, msg = "Operands cannot be identical"}
|
||||
end
|
||||
if compare_op(elem.op1, elem.dst, true) or compare_op(elem.op2, elem.dst, true) then
|
||||
return {i = i, msg = "Destination and operands must be different"}
|
||||
end
|
||||
-- check whether operands point to defined registers
|
||||
if elem.op1 ~= nil and elem.op1.type == "reg"
|
||||
and not is_reg_written_to(t, elem.op1.n, i) then
|
||||
return {i = i, msg = "First operand is undefined register"}
|
||||
end
|
||||
if elem.op2.type == "reg" and not is_reg_written_to(t, elem.op2.n, i) then
|
||||
return {i = i, msg = "Second operand is undefined register"}
|
||||
end
|
||||
-- check whether destination points to undefined register
|
||||
if elem.dst.type == "reg" and is_reg_written_to(t, elem.dst.n, i) then
|
||||
return {i = i, msg = "Destination is already used register"}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
lg.validate = function(t)
|
||||
for i = 1, 14 do
|
||||
if next(t[i]) ~= nil then
|
||||
local r = lg.validate_single(t, i)
|
||||
if r ~= nil then
|
||||
return r
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- interpreter
|
||||
lg.interpret = function(t, a, b, c, d)
|
||||
local function _action(s, v1, v2)
|
||||
if s == "and" then
|
||||
return v1 and v2
|
||||
elseif s == "or" then
|
||||
return v1 or v2
|
||||
elseif s == "not" then
|
||||
return not v2
|
||||
elseif s == "xor" then
|
||||
return v1 ~= v2
|
||||
elseif s == "nand" then
|
||||
return not (v1 and v2)
|
||||
elseif s == "buf" then
|
||||
return v2
|
||||
else -- s == "xnor"
|
||||
return v1 == v2
|
||||
end
|
||||
end
|
||||
local function _op(t, regs, io_in)
|
||||
if t.type == "reg" then
|
||||
return regs[t.n]
|
||||
else -- t.type == "io"
|
||||
return io_in[t.port]
|
||||
end
|
||||
end
|
||||
|
||||
local io_in = {A=a, B=b, C=c, D=d}
|
||||
local regs = {}
|
||||
local io_out = {}
|
||||
for i = 1, 14 do
|
||||
local cur = t[i]
|
||||
if next(cur) ~= nil then
|
||||
local v1, v2
|
||||
if cur.op1 ~= nil then
|
||||
v1 = _op(cur.op1, regs, io_in)
|
||||
end
|
||||
v2 = _op(cur.op2, regs, io_in)
|
||||
|
||||
local result = _action(cur.action, v1, v2)
|
||||
|
||||
if cur.dst.type == "reg" then
|
||||
regs[cur.dst.n] = result
|
||||
else -- cur.dst.type == "io"
|
||||
io_out[cur.dst.port] = result
|
||||
end
|
||||
end
|
||||
end
|
||||
return io_out.A, io_out.B, io_out.C, io_out.D
|
||||
end
|
||||
|
||||
return lg
|
Before Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 536 B |
Before Width: | Height: | Size: 816 B |
@ -1,62 +0,0 @@
|
||||
return function(plg)
|
||||
|
||||
|
||||
minetest.register_tool("mesecons_fpga:programmer", {
|
||||
description = "FPGA Programmer",
|
||||
inventory_image = "jeija_fpga_programmer.png",
|
||||
stack_max = 1,
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local pos = pointed_thing.under
|
||||
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("instr") == "//////////////" then
|
||||
minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.")
|
||||
return itemstack
|
||||
end
|
||||
itemstack:set_metadata(meta:get_string("instr"))
|
||||
minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!")
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local pos = pointed_thing.under
|
||||
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local imeta = itemstack:get_metadata()
|
||||
if imeta == "" then
|
||||
minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.")
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("instr", imeta)
|
||||
plg.update_formspec(pos, imeta)
|
||||
minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!")
|
||||
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mesecons_fpga:programmer",
|
||||
recipe = {
|
||||
{'group:mesecon_conductor_craftable'},
|
||||
{'mesecons_materials:silicon'},
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
end
|
@ -1,2 +0,0 @@
|
||||
AND gates power their output if both inputs (from left and right) are powered.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 2.7 KiB |
@ -1,2 +0,0 @@
|
||||
Diodes conduct signals in one direction only.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 2.0 KiB |
@ -1,2 +0,0 @@
|
||||
NAND gates do not power their output if both inputs (from left and right) are powered, but power it in every other case.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 2.7 KiB |
@ -1,2 +0,0 @@
|
||||
NOR gates only power their output if none of their two inputs is powered. They are basically OR gates with a NOT gate at their output.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 2.4 KiB |
@ -1,2 +0,0 @@
|
||||
NOT gates invert signals, just like a mesecon torch does, but faster. The input is at the opposite side of the output.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 2.0 KiB |
@ -1,2 +0,0 @@
|
||||
OR gates power their output if either of their inputs (or both) are powered. You could basically get the same behaviour with two diodes, but OR gates save some space.
|
||||
They work in unloaded blocks.
|
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 2.4 KiB |
@ -1,2 +0,0 @@
|
||||
XOR gates power their output if only one input is powered, they're off if either both or none of the inputs is powered.
|
||||
They work in unloaded blocks.
|