Compare commits
99 Commits
2016.09.13
...
e1cffdedbf
Author | SHA1 | Date | |
---|---|---|---|
e1cffdedbf | |||
d3aedd2b98 | |||
68c1729990 | |||
9b58f8db29 | |||
7784b13da5 | |||
0dd530312b | |||
e78bbd6f98 | |||
bfd952b51a | |||
b7873e8e02 | |||
d6b2a39c99 | |||
1b54011b68 | |||
15e743629e | |||
1bf862f932 | |||
1a9704f184 | |||
8baa789eb1 | |||
b0158f5674 | |||
073c92d487 | |||
737f366741 | |||
302a28934d | |||
6e767a6c76 | |||
9d239cbfff | |||
d3cabedbb0 | |||
df4e880d8b | |||
45bbd9f7e3 | |||
028c290cd7 | |||
8808bb8911 | |||
fa040eb085 | |||
a4f5ae5b89 | |||
9e6eac4285 | |||
c73b451f9b | |||
9ff2329253 | |||
444cd0f2f1 | |||
d4e05f33af | |||
334400a541 | |||
5a0492b176 | |||
f61b1affea | |||
a234006592 | |||
12fb09f452 | |||
ff73d0e60f | |||
7013f2e5d4 | |||
f70a308bb0 | |||
d8f82e6771 | |||
7537b9f381 | |||
5ae3354227 | |||
1b513d2111 | |||
6f1ff24474 | |||
065e870349 | |||
fec82ab246 | |||
02f8d29170 | |||
2b096f050d | |||
993fdedd8c | |||
ff0bd76efe | |||
db39eef2f6 | |||
f78937b351 | |||
cc860acf8a | |||
748446b3cc | |||
1b10610f92 | |||
4f400f3fae | |||
7094f0b606 | |||
b08e93fc8b | |||
928f04fa9c | |||
c4a1aa0b98 | |||
37eb7f00e8 | |||
905260c8db | |||
8999597df2 | |||
0b3039e9a9 | |||
1f5601661e | |||
fa58607546 | |||
1963d8b3d5 | |||
954262d016 | |||
3ef8ae01e7 | |||
42cd973921 | |||
36a6419481 | |||
564bdc2d9b | |||
f9ebbdc0fb | |||
4dcc7fb32f | |||
54b9eaffa2 | |||
2554164674 | |||
967bde284a | |||
d80c788fab | |||
03ab151c87 | |||
dd2b36c41c | |||
0cb286b425 | |||
46cbc76988 | |||
fa3bd19270 | |||
2bc3c5d97c | |||
07d074075c | |||
5188853014 | |||
7667e7d8c5 | |||
ececf525b6 | |||
54daee236e | |||
c2e3d7c4e5 | |||
7415036f5b | |||
1bd936ad8c | |||
79edbed8d7 | |||
8743699298 | |||
703e6fdadb | |||
67cd17aa79 | |||
203aaf3c90 |
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
*~
|
*~
|
||||||
|
*.patch
|
||||||
|
*.diff
|
||||||
|
@ -22,9 +22,9 @@ OK, I want in.
|
|||||||
--------------
|
--------------
|
||||||
Go get it!
|
Go get it!
|
||||||
|
|
||||||
[DOWNLOAD IT NOW](https://github.com/Jeija/minetest-mod-mesecons/archive/master.zip)
|
[DOWNLOAD IT NOW](https://github.com/minetest-mods/mesecons/archive/master.zip)
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
||||||
1. If Mesecons is still in a ZIP file, extract the folder inside to somewhere on the computer.
|
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.
|
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.
|
||||||
@ -43,9 +43,11 @@ Or maybe a [comprehensive reference](http://mesecons.net/items.html) is your sty
|
|||||||
|
|
||||||
An overview for the very newest of new beginners? How does [this one](http://uberi.mesecons.net/projects/MeseconsBasics/index.html) look?
|
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 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/Jeija/minetest-mod-mesecons)!
|
Want to contribute to Mesecons itself? Check out the [source code](https://github.com/minetest-mods/mesecons)!
|
||||||
|
|
||||||
Who wrote it anyways?
|
Who wrote it anyways?
|
||||||
---------------------
|
---------------------
|
||||||
|
12
bower.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
@ -42,6 +42,8 @@
|
|||||||
},
|
},
|
||||||
"Logic" : {
|
"Logic" : {
|
||||||
"Luacontroller" : "mesecons_luacontroller/doc/luacontroller",
|
"Luacontroller" : "mesecons_luacontroller/doc/luacontroller",
|
||||||
|
"FPGA" : "mesecons_fpga/doc/fpga",
|
||||||
|
"FPGA Programmer" : "mesecons_fpga/doc/programmer",
|
||||||
"Torch" : "mesecons_torch/doc/torch",
|
"Torch" : "mesecons_torch/doc/torch",
|
||||||
"Delayer" : "mesecons_delayer/doc/delayer",
|
"Delayer" : "mesecons_delayer/doc/delayer",
|
||||||
"Gates" : {
|
"Gates" : {
|
||||||
|
@ -1,96 +1,140 @@
|
|||||||
mesecon.queue.actions={} -- contains all ActionQueue actions
|
--[[
|
||||||
|
Mesecons uses something it calls an ActionQueue.
|
||||||
|
|
||||||
function mesecon.queue:add_function(name, func)
|
The ActionQueue holds functions and actions.
|
||||||
mesecon.queue.funcs[name] = func
|
Functions are added on load time with a specified name.
|
||||||
|
Actions are preserved over server restarts.
|
||||||
|
|
||||||
|
Each action consists of a position, the name of an added function to be called,
|
||||||
|
the params that should be used in this function call (additionally to the pos),
|
||||||
|
the time after which it should be executed, an optional overwritecheck and a
|
||||||
|
priority.
|
||||||
|
|
||||||
|
If time = 0, the action will be executed in the next globalstep, otherwise the
|
||||||
|
earliest globalstep when it will be executed is the after next globalstep.
|
||||||
|
|
||||||
|
It is guaranteed, that for two actions ac1, ac2 where ac1 ~= ac2,
|
||||||
|
ac1.time == ac2.time, ac1.priority == ac2.priority and ac1 was added earlier
|
||||||
|
than ac2, ac1 will be executed before ac2 (but in the same globalstep).
|
||||||
|
|
||||||
|
Note: Do not pass references in params, as they can not be preserved.
|
||||||
|
|
||||||
|
Also note: Some of the guarantees here might be dropped at some time.
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
-- localize for speed
|
||||||
|
local queue = mesecon.queue
|
||||||
|
|
||||||
|
queue.actions = {} -- contains all ActionQueue actions
|
||||||
|
|
||||||
|
function queue:add_function(name, func)
|
||||||
|
queue.funcs[name] = func
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
|
-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
|
||||||
-- use overwritecheck nil to never overwrite, but just add the event to the queue
|
-- use overwritecheck nil to never overwrite, but just add the event to the queue
|
||||||
-- priority specifies the order actions are executed within one globalstep, highest first
|
-- priority specifies the order actions are executed within one globalstep, highest first
|
||||||
-- should be between 0 and 1
|
-- should be between 0 and 1
|
||||||
function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
|
function queue:add_action(pos, func, params, time, overwritecheck, priority)
|
||||||
-- Create Action Table:
|
-- Create Action Table:
|
||||||
time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
|
time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
|
||||||
priority = priority or 1
|
priority = priority or 1
|
||||||
local action = { pos=mesecon.tablecopy(pos),
|
local action = {
|
||||||
func=func,
|
pos = mesecon.tablecopy(pos),
|
||||||
params=mesecon.tablecopy(params or {}),
|
func = func,
|
||||||
time=time,
|
params = mesecon.tablecopy(params or {}),
|
||||||
owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
|
time = time,
|
||||||
priority=priority}
|
owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
|
||||||
|
priority = priority
|
||||||
|
}
|
||||||
|
|
||||||
local toremove = nil
|
-- check if old action has to be overwritten / removed:
|
||||||
-- Otherwise, add the action to the queue
|
if overwritecheck then
|
||||||
if overwritecheck then -- check if old action has to be overwritten / removed:
|
for i, ac in ipairs(queue.actions) do
|
||||||
for i, ac in ipairs(mesecon.queue.actions) do
|
if vector.equals(pos, ac.pos)
|
||||||
if(vector.equals(pos, ac.pos)
|
and mesecon.cmpAny(overwritecheck, ac.owcheck) then
|
||||||
and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
|
-- remove the old action
|
||||||
toremove = i
|
table.remove(queue.actions, i)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (toremove ~= nil) then
|
table.insert(queue.actions, action)
|
||||||
table.remove(mesecon.queue.actions, toremove)
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(mesecon.queue.actions, action)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- execute the stored functions on a globalstep
|
-- execute the stored functions on a globalstep
|
||||||
-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
|
-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
|
||||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine
|
-- this makes sure that resuming mesecons circuits when restarting minetest works fine (hm, where do we do this?)
|
||||||
-- However, even that does not work in some cases, that's why we delay the time the globalsteps
|
-- However, even that does not work in some cases, that's why we delay the time the globalsteps
|
||||||
-- start to be execute by 5 seconds
|
-- start to be execute by 4 seconds
|
||||||
local get_highest_priority = function (actions)
|
|
||||||
local highestp = -1
|
|
||||||
local highesti
|
|
||||||
for i, ac in ipairs(actions) do
|
|
||||||
if ac.priority > highestp then
|
|
||||||
highestp = ac.priority
|
|
||||||
highesti = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return highesti
|
local function globalstep_func(dtime)
|
||||||
end
|
local actions = queue.actions
|
||||||
|
-- split into two categories:
|
||||||
|
-- actions_now: actions to execute now
|
||||||
|
-- queue.actions: actions to execute later
|
||||||
|
local actions_now = {}
|
||||||
|
queue.actions = {}
|
||||||
|
|
||||||
local m_time = 0
|
for _, ac in ipairs(actions) do
|
||||||
local resumetime = mesecon.setting("resumetime", 4)
|
|
||||||
minetest.register_globalstep(function (dtime)
|
|
||||||
m_time = m_time + dtime
|
|
||||||
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
|
|
||||||
-- after starting the server before processing the ActionQueue, don't set this too low
|
|
||||||
if (m_time < resumetime) then return end
|
|
||||||
local actions = mesecon.tablecopy(mesecon.queue.actions)
|
|
||||||
local actions_now={}
|
|
||||||
|
|
||||||
mesecon.queue.actions = {}
|
|
||||||
|
|
||||||
-- sort actions into two categories:
|
|
||||||
-- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions)
|
|
||||||
for i, ac in ipairs(actions) do
|
|
||||||
if ac.time > 0 then
|
if ac.time > 0 then
|
||||||
ac.time = ac.time - dtime -- executed later
|
-- action ac is to be executed later
|
||||||
table.insert(mesecon.queue.actions, ac)
|
-- ~> insert into queue.actions
|
||||||
|
ac.time = ac.time - dtime
|
||||||
|
table.insert(queue.actions, ac)
|
||||||
else
|
else
|
||||||
|
-- action ac is to be executed now
|
||||||
|
-- ~> insert into actions_now
|
||||||
table.insert(actions_now, ac)
|
table.insert(actions_now, ac)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
while(#actions_now > 0) do -- execute highest priorities first, until all are executed
|
-- stable-sort the executed actions after their priority
|
||||||
local hp = get_highest_priority(actions_now)
|
-- some constructions might depend on the execution order, hence we first
|
||||||
mesecon.queue:execute(actions_now[hp])
|
-- execute the actions that had a lower index in actions_now
|
||||||
table.remove(actions_now, hp)
|
local old_action_order = {}
|
||||||
|
for i, ac in ipairs(actions_now) do
|
||||||
|
old_action_order[ac] = i
|
||||||
end
|
end
|
||||||
end)
|
table.sort(actions_now, function(ac1, ac2)
|
||||||
|
if ac1.priority ~= ac2.priority then
|
||||||
|
return ac1.priority > ac2.priority
|
||||||
|
else
|
||||||
|
return old_action_order[ac1] < old_action_order[ac2]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
function mesecon.queue:execute(action)
|
-- execute highest priorities first, until all are executed
|
||||||
|
for _, ac in ipairs(actions_now) do
|
||||||
|
queue:execute(ac)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- delay the time the globalsteps start to be execute by 4 seconds
|
||||||
|
do
|
||||||
|
local m_time = 0
|
||||||
|
local resumetime = mesecon.setting("resumetime", 4)
|
||||||
|
local globalstep_func_index = #minetest.registered_globalsteps + 1
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
m_time = m_time + dtime
|
||||||
|
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
|
||||||
|
-- after starting the server before processing the ActionQueue, don't set this too low
|
||||||
|
if m_time < resumetime then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- replace this globalstep function
|
||||||
|
minetest.registered_globalsteps[globalstep_func_index] = globalstep_func
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function queue:execute(action)
|
||||||
-- ignore if action queue function name doesn't exist,
|
-- ignore if action queue function name doesn't exist,
|
||||||
-- (e.g. in case the action queue savegame was written by an old mesecons version)
|
-- (e.g. in case the action queue savegame was written by an old mesecons version)
|
||||||
if mesecon.queue.funcs[action.func] then
|
if queue.funcs[action.func] then
|
||||||
mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
|
queue.funcs[action.func](action.pos, unpack(action.params))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -98,8 +142,8 @@ end
|
|||||||
-- Store and read the ActionQueue to / from a file
|
-- Store and read the ActionQueue to / from a file
|
||||||
-- so that upcoming actions are remembered when the game
|
-- so that upcoming actions are remembered when the game
|
||||||
-- is restarted
|
-- is restarted
|
||||||
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
|
queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||||
|
|
||||||
minetest.register_on_shutdown(function()
|
minetest.register_on_shutdown(function()
|
||||||
mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
|
mesecon.table2file("mesecon_actionqueue", queue.actions)
|
||||||
end)
|
end)
|
||||||
|
@ -548,52 +548,3 @@ function mesecon.is_powered(pos, rule)
|
|||||||
if (#sourcepos == 0) then return false
|
if (#sourcepos == 0) then return false
|
||||||
else return sourcepos end
|
else return sourcepos end
|
||||||
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
|
|
||||||
|
@ -4,7 +4,7 @@ minetest.register_node("mesecons:mesecon_off", {
|
|||||||
inventory_image = "jeija_mesecon_off.png",
|
inventory_image = "jeija_mesecon_off.png",
|
||||||
wield_image = "jeija_mesecon_off.png",
|
wield_image = "jeija_mesecon_off.png",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
is_ground_content = true,
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
@ -22,7 +22,7 @@ minetest.register_node("mesecons:mesecon_on", {
|
|||||||
drawtype = "raillike",
|
drawtype = "raillike",
|
||||||
tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"},
|
tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
is_ground_content = true,
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
@ -30,7 +30,7 @@ minetest.register_node("mesecons:mesecon_on", {
|
|||||||
},
|
},
|
||||||
groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1},
|
groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1},
|
||||||
drop = "mesecons:mesecon_off 1",
|
drop = "mesecons:mesecon_off 1",
|
||||||
light_source = default.LIGHT_MAX-11,
|
light_source = minetest.LIGHT_MAX-11,
|
||||||
mesecons = {conductor={
|
mesecons = {conductor={
|
||||||
state = mesecon.state.on,
|
state = mesecon.state.on,
|
||||||
offstate = "mesecons:mesecon_off"
|
offstate = "mesecons:mesecon_off"
|
||||||
|
@ -1,54 +1,85 @@
|
|||||||
mesecon.rules = {}
|
mesecon.rules = {}
|
||||||
mesecon.state = {}
|
mesecon.state = {}
|
||||||
|
|
||||||
mesecon.rules.default =
|
mesecon.rules.default = {
|
||||||
{{x=0, y=0, z=-1},
|
{x = 0, y = 0, z = -1},
|
||||||
{x=1, y=0, z=0},
|
{x = 1, y = 0, z = 0},
|
||||||
{x=-1, y=0, z=0},
|
{x = -1, y = 0, z = 0},
|
||||||
{x=0, y=0, z=1},
|
|
||||||
{x=1, y=1, z=0},
|
|
||||||
{x=1, y=-1, z=0},
|
|
||||||
{x=-1, y=1, z=0},
|
|
||||||
{x=-1, y=-1, z=0},
|
|
||||||
{x=0, y=1, z=1},
|
|
||||||
{x=0, y=-1, z=1},
|
|
||||||
{x=0, y=1, z=-1},
|
|
||||||
{x=0, y=-1, z=-1}}
|
|
||||||
|
|
||||||
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}})
|
|
||||||
|
|
||||||
mesecon.rules.buttonlike =
|
|
||||||
{{x = 1, y = 0, z = 0},
|
|
||||||
{x = 1, y = 1, z = 0},
|
|
||||||
{x = 1, y =-1, z = 0},
|
|
||||||
{x = 1, y =-1, z = 1},
|
|
||||||
{x = 1, y =-1, z =-1},
|
|
||||||
{x = 2, y = 0, z = 0}}
|
|
||||||
|
|
||||||
mesecon.rules.flat =
|
|
||||||
{{x = 1, y = 0, z = 0},
|
|
||||||
{x =-1, y = 0, z = 0},
|
|
||||||
{x = 0, y = 0, z = 1},
|
{x = 0, y = 0, z = 1},
|
||||||
{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.alldirs =
|
mesecon.rules.floor = mesecon.mergetable(mesecon.rules.default, {{x = 0, y = -1, z = 0}})
|
||||||
{{x= 1, y= 0, z= 0},
|
|
||||||
{x=-1, y= 0, z= 0},
|
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.floor, {{x = 0, y = -2, z = 0}})
|
||||||
{x= 0, y= 1, z= 0},
|
|
||||||
{x= 0, y=-1, z= 0},
|
mesecon.rules.buttonlike = {
|
||||||
{x= 0, y= 0, z= 1},
|
{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 = 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.buttonlike_get = function(node)
|
mesecon.rules.buttonlike_get = function(node)
|
||||||
local rules = mesecon.rules.buttonlike
|
local dir = minetest.facedir_to_dir(node.param2)
|
||||||
if node.param2 == 2 then
|
return rules_from_dir(rules_buttonlike, dir)
|
||||||
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
|
end
|
||||||
|
|
||||||
mesecon.state.on = "on"
|
mesecon.state.on = "on"
|
||||||
|
@ -21,7 +21,8 @@ mesecon.on_placenode = function(pos, node)
|
|||||||
end
|
end
|
||||||
--mesecon.receptor_on (pos, mesecon.conductor_get_rules(node))
|
--mesecon.receptor_on (pos, mesecon.conductor_get_rules(node))
|
||||||
elseif mesecon.is_conductor_on(node) then
|
elseif mesecon.is_conductor_on(node) then
|
||||||
minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)})
|
node.name = mesecon.get_conductor_off(node)
|
||||||
|
minetest.swap_node(pos, node)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -62,34 +63,74 @@ mesecon.on_dignode = function(pos, node)
|
|||||||
mesecon.execute_autoconnect_hooks_queue(pos, node)
|
mesecon.execute_autoconnect_hooks_queue(pos, node)
|
||||||
end
|
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
|
||||||
|
|
||||||
minetest.register_on_placenode(mesecon.on_placenode)
|
minetest.register_on_placenode(mesecon.on_placenode)
|
||||||
minetest.register_on_dignode(mesecon.on_dignode)
|
minetest.register_on_dignode(mesecon.on_dignode)
|
||||||
|
|
||||||
-- Overheating service for fast circuits
|
-- 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
|
-- returns true if heat is too high
|
||||||
mesecon.do_overheat = function(pos)
|
function mesecon.do_overheat(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local id = minetest.hash_node_position(pos)
|
||||||
local heat = meta:get_int("heat") or 0
|
local heat = (object_heat[id] or 0) + 1
|
||||||
|
object_heat[id] = heat
|
||||||
heat = heat + 1
|
if heat >= OVERHEAT_MAX then
|
||||||
meta:set_int("heat", heat)
|
minetest.log("action", "Node overheats at " .. minetest.pos_to_string(pos))
|
||||||
|
object_heat[id] = nil
|
||||||
if heat < mesecon.setting("overheat_max", 20) then
|
|
||||||
mesecon.queue:add_action(pos, "cooldown", {}, 1, nil, 0)
|
|
||||||
else
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mesecon.do_cooldown(pos)
|
||||||
|
local id = minetest.hash_node_position(pos)
|
||||||
|
object_heat[id] = nil
|
||||||
|
end
|
||||||
|
|
||||||
mesecon.queue:add_function("cooldown", function (pos)
|
function mesecon.get_heat(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local id = minetest.hash_node_position(pos)
|
||||||
local heat = meta:get_int("heat")
|
return object_heat[id] or 0
|
||||||
|
end
|
||||||
|
|
||||||
if (heat > 0) then
|
function mesecon.move_hot_nodes(moved_nodes)
|
||||||
meta:set_int("heat", heat - 1)
|
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
|
end
|
||||||
end)
|
for id, heat in pairs(new_heat) do
|
||||||
|
object_heat[id] = heat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function global_cooldown(dtime)
|
||||||
|
cooldown_timer = cooldown_timer + dtime
|
||||||
|
if cooldown_timer < COOLDOWN_STEP then
|
||||||
|
return -- don't overload the CPU
|
||||||
|
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)
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
-- SETTINGS
|
-- SETTINGS
|
||||||
function mesecon.setting(setting, default)
|
function mesecon.setting(setting, default)
|
||||||
if type(default) == "boolean" then
|
if type(default) == "boolean" then
|
||||||
local read = minetest.setting_getbool("mesecon."..setting)
|
local read = minetest.settings:get_bool("mesecon."..setting)
|
||||||
if read == nil then
|
if read == nil then
|
||||||
return default
|
return default
|
||||||
else
|
else
|
||||||
return read
|
return read
|
||||||
end
|
end
|
||||||
elseif type(default) == "string" then
|
elseif type(default) == "string" then
|
||||||
return minetest.setting_get("mesecon."..setting) or default
|
return minetest.settings:get("mesecon."..setting) or default
|
||||||
elseif type(default) == "number" then
|
elseif type(default) == "number" then
|
||||||
return tonumber(minetest.setting_get("mesecon."..setting) or default)
|
return tonumber(minetest.settings:get("mesecon."..setting) or default)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 191 B |
BIN
mesecons/textures/jeija_microcontroller_LED_A.png
Normal file
After Width: | Height: | Size: 844 B |
BIN
mesecons/textures/jeija_microcontroller_LED_B.png
Normal file
After Width: | Height: | Size: 838 B |
BIN
mesecons/textures/jeija_microcontroller_LED_C.png
Normal file
After Width: | Height: | Size: 851 B |
BIN
mesecons/textures/jeija_microcontroller_LED_D.png
Normal file
After Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 550 B After Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 204 B After Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 362 B |
@ -6,6 +6,56 @@ function mesecon.move_node(pos, newpos)
|
|||||||
minetest.get_meta(pos):from_table(meta)
|
minetest.get_meta(pos):from_table(meta)
|
||||||
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
|
||||||
|
--
|
||||||
|
|
||||||
function mesecon.flattenrules(allrules)
|
function mesecon.flattenrules(allrules)
|
||||||
--[[
|
--[[
|
||||||
{
|
{
|
||||||
@ -136,19 +186,11 @@ function mesecon.invertRule(r)
|
|||||||
return vector.multiply(r, -1)
|
return vector.multiply(r, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.tablecopy(table) -- deep table copy
|
function mesecon.tablecopy(obj) -- deep copy
|
||||||
if type(table) ~= "table" then return table end -- no need to copy
|
if type(obj) == "table" then
|
||||||
local newtable = {}
|
return table.copy(obj)
|
||||||
|
|
||||||
for idx, item in pairs(table) do
|
|
||||||
if type(item) == "table" then
|
|
||||||
newtable[idx] = mesecon.tablecopy(item)
|
|
||||||
else
|
|
||||||
newtable[idx] = item
|
|
||||||
end
|
end
|
||||||
end
|
return obj
|
||||||
|
|
||||||
return newtable
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mesecon.cmpAny(t1, t2)
|
function mesecon.cmpAny(t1, t2)
|
||||||
@ -178,6 +220,7 @@ end
|
|||||||
|
|
||||||
function mesecon.register_node(name, spec_common, spec_off, spec_on)
|
function mesecon.register_node(name, spec_common, spec_off, spec_on)
|
||||||
spec_common.drop = spec_common.drop or name .. "_off"
|
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_common.__mesecon_basename = name
|
||||||
spec_on.__mesecon_state = "on"
|
spec_on.__mesecon_state = "on"
|
||||||
spec_off.__mesecon_state = "off"
|
spec_off.__mesecon_state = "off"
|
||||||
@ -231,11 +274,6 @@ local function hash_blockpos(pos)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- convert block hash --> node position
|
|
||||||
local function unhash_blockpos(hash)
|
|
||||||
return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
|
-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
|
||||||
-- table.
|
-- table.
|
||||||
--
|
--
|
||||||
|
@ -1 +1,2 @@
|
|||||||
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.
|
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.
|
||||||
|
BIN
mesecons_blinkyplant/doc/blinkyplant/preview.png
Executable file → Normal file
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.7 KiB |
@ -24,6 +24,7 @@ mesecon.register_node("mesecons_blinkyplant:blinky_plant", {
|
|||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
inventory_image = "jeija_blinky_plant_off.png",
|
inventory_image = "jeija_blinky_plant_off.png",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
sounds = default.node_sound_leaves_defaults(),
|
sounds = default.node_sound_leaves_defaults(),
|
||||||
selection_box = {
|
selection_box = {
|
||||||
|
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 394 B |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 4.3 KiB |
@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
mesecon.button_turnoff = function (pos)
|
mesecon.button_turnoff = function (pos)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
if node.name=="mesecons_button:button_on" then --has not been dug
|
if node.name ~= "mesecons_button:button_on" then -- has been dug
|
||||||
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2=node.param2})
|
return
|
||||||
minetest.sound_play("mesecons_button_pop", {pos=pos})
|
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)
|
local rules = mesecon.rules.buttonlike_get(node)
|
||||||
mesecon.receptor_off(pos, rules)
|
mesecon.receptor_off(pos, rules)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_node("mesecons_button:button_off", {
|
minetest.register_node("mesecons_button:button_off", {
|
||||||
@ -24,8 +25,10 @@ minetest.register_node("mesecons_button:button_off", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
legacy_wallmounted = true,
|
legacy_wallmounted = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
|
on_rotate = mesecon.buttonlike_onrotate,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
@ -44,13 +47,14 @@ minetest.register_node("mesecons_button:button_off", {
|
|||||||
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
|
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
|
||||||
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
|
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
|
||||||
minetest.sound_play("mesecons_button_push", {pos=pos})
|
minetest.sound_play("mesecons_button_push", {pos=pos})
|
||||||
minetest.after(1, mesecon.button_turnoff, pos)
|
minetest.get_node_timer(pos):start(1)
|
||||||
end,
|
end,
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
mesecons = {receptor = {
|
mesecons = {receptor = {
|
||||||
state = mesecon.state.off,
|
state = mesecon.state.off,
|
||||||
rules = mesecon.rules.buttonlike_get
|
rules = mesecon.rules.buttonlike_get
|
||||||
}}
|
}},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_button:button_on", {
|
minetest.register_node("mesecons_button:button_on", {
|
||||||
@ -65,9 +69,11 @@ minetest.register_node("mesecons_button:button_on", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
legacy_wallmounted = true,
|
legacy_wallmounted = true,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
light_source = default.LIGHT_MAX-7,
|
on_rotate = false,
|
||||||
|
light_source = minetest.LIGHT_MAX-7,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
@ -87,7 +93,9 @@ minetest.register_node("mesecons_button:button_on", {
|
|||||||
mesecons = {receptor = {
|
mesecons = {receptor = {
|
||||||
state = mesecon.state.on,
|
state = mesecon.state.on,
|
||||||
rules = mesecon.rules.buttonlike_get
|
rules = mesecon.rules.buttonlike_get
|
||||||
}}
|
}},
|
||||||
|
on_timer = mesecon.button_turnoff,
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 409 B |
Before Width: | Height: | Size: 434 B After Width: | Height: | Size: 220 B |
@ -1 +1,2 @@
|
|||||||
There is no crafting recipe as this should only be available for server admins. Quite similar to the Minecraft counterpart. Executes server commands.
|
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 After Width: | Height: | Size: 33 KiB |
@ -181,6 +181,7 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
|
|||||||
description = "Command Block",
|
description = "Command Block",
|
||||||
tiles = {"jeija_commandblock_off.png"},
|
tiles = {"jeija_commandblock_off.png"},
|
||||||
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
|
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
|
||||||
|
is_ground_content = false,
|
||||||
groups = {cracky=2, mesecon_effector_off=1},
|
groups = {cracky=2, mesecon_effector_off=1},
|
||||||
on_construct = construct,
|
on_construct = construct,
|
||||||
after_place_node = after_place,
|
after_place_node = after_place,
|
||||||
@ -189,11 +190,13 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
|
|||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
mesecons = {effector = {
|
mesecons = {effector = {
|
||||||
action_on = commandblock_action_on
|
action_on = commandblock_action_on
|
||||||
}}
|
}},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_commandblock:commandblock_on", {
|
minetest.register_node("mesecons_commandblock:commandblock_on", {
|
||||||
tiles = {"jeija_commandblock_on.png"},
|
tiles = {"jeija_commandblock_on.png"},
|
||||||
|
is_ground_content = false,
|
||||||
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
|
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
|
||||||
light_source = 10,
|
light_source = 10,
|
||||||
drop = "mesecons_commandblock:commandblock_off",
|
drop = "mesecons_commandblock:commandblock_off",
|
||||||
@ -204,5 +207,6 @@ minetest.register_node("mesecons_commandblock:commandblock_on", {
|
|||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
mesecons = {effector = {
|
mesecons = {effector = {
|
||||||
action_off = commandblock_action_off
|
action_off = commandblock_action_off
|
||||||
}}
|
}},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 183 B |
@ -1 +1 @@
|
|||||||
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.
|
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 After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 4.2 KiB |
@ -33,21 +33,12 @@ end
|
|||||||
|
|
||||||
-- Register the 2 (states) x 4 (delay times) delayers
|
-- Register the 2 (states) x 4 (delay times) delayers
|
||||||
|
|
||||||
|
local delaytime = { 0.1, 0.3, 0.5, 1.0 }
|
||||||
|
|
||||||
for i = 1, 4 do
|
for i = 1, 4 do
|
||||||
local groups = {}
|
|
||||||
if i == 1 then
|
|
||||||
groups = {bendy=2,snappy=1,dig_immediate=2}
|
|
||||||
else
|
|
||||||
groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1}
|
|
||||||
end
|
|
||||||
|
|
||||||
local delaytime
|
local boxes = {
|
||||||
if i == 1 then delaytime = 0.1
|
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
||||||
elseif i == 2 then delaytime = 0.3
|
|
||||||
elseif i == 3 then delaytime = 0.5
|
|
||||||
elseif i == 4 then delaytime = 1.0 end
|
|
||||||
|
|
||||||
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
|
{ -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 },
|
{ -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 },
|
||||||
@ -57,11 +48,39 @@ boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
|||||||
|
|
||||||
{ -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator
|
{ -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
|
{ -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), {
|
-- Delayer definition defaults
|
||||||
description = "Delayer",
|
local def = {
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
|
walkable = true,
|
||||||
|
selection_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
||||||
|
},
|
||||||
|
node_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = boxes
|
||||||
|
},
|
||||||
|
paramtype = "light",
|
||||||
|
paramtype2 = "facedir",
|
||||||
|
sunlight_propagates = true,
|
||||||
|
is_ground_content = false,
|
||||||
|
delayer_time = delaytime[i],
|
||||||
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
|
drop = "mesecons_delayer:delayer_off_1",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Deactivated delayer definition defaults
|
||||||
|
local off_groups = {bendy=2,snappy=1,dig_immediate=2}
|
||||||
|
if i > 1 then
|
||||||
|
off_groups.not_in_creative_inventory = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local off_state = {
|
||||||
|
description = "Delayer",
|
||||||
tiles = {
|
tiles = {
|
||||||
"mesecons_delayer_off_"..tostring(i)..".png",
|
"mesecons_delayer_off_"..tostring(i)..".png",
|
||||||
"mesecons_delayer_bottom.png",
|
"mesecons_delayer_bottom.png",
|
||||||
@ -72,35 +91,18 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
|||||||
},
|
},
|
||||||
inventory_image = "mesecons_delayer_off_1.png",
|
inventory_image = "mesecons_delayer_off_1.png",
|
||||||
wield_image = "mesecons_delayer_off_1.png",
|
wield_image = "mesecons_delayer_off_1.png",
|
||||||
walkable = true,
|
groups = off_groups,
|
||||||
selection_box = {
|
on_punch = function(pos, node, puncher)
|
||||||
type = "fixed",
|
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
return
|
||||||
},
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = boxes
|
|
||||||
},
|
|
||||||
groups = groups,
|
|
||||||
paramtype = "light",
|
|
||||||
paramtype2 = "facedir",
|
|
||||||
sunlight_propagates = true,
|
|
||||||
is_ground_content = true,
|
|
||||||
drop = 'mesecons_delayer:delayer_off_1',
|
|
||||||
on_punch = function (pos, node)
|
|
||||||
if node.name=="mesecons_delayer:delayer_off_1" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_2", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_off_2" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_3", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_off_3" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_4", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_off_4" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_1", param2=node.param2})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
minetest.swap_node(pos, {
|
||||||
|
name = "mesecons_delayer:delayer_off_"..tostring(i % 4 + 1),
|
||||||
|
param2 = node.param2
|
||||||
|
})
|
||||||
end,
|
end,
|
||||||
delayer_time = delaytime,
|
|
||||||
delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
|
delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
|
||||||
sounds = default.node_sound_stone_defaults(),
|
|
||||||
mesecons = {
|
mesecons = {
|
||||||
receptor =
|
receptor =
|
||||||
{
|
{
|
||||||
@ -112,13 +114,16 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
|||||||
rules = delayer_get_input_rules,
|
rules = delayer_get_input_rules,
|
||||||
action_on = delayer_activate
|
action_on = delayer_activate
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
}
|
||||||
|
for k, v in pairs(def) do
|
||||||
|
off_state[k] = off_state[k] or v
|
||||||
|
end
|
||||||
|
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state)
|
||||||
|
|
||||||
|
-- Activated delayer definition defaults
|
||||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
local on_state = {
|
||||||
description = "You hacker you",
|
description = "You hacker you",
|
||||||
drawtype = "nodebox",
|
|
||||||
tiles = {
|
tiles = {
|
||||||
"mesecons_delayer_on_"..tostring(i)..".png",
|
"mesecons_delayer_on_"..tostring(i)..".png",
|
||||||
"mesecons_delayer_bottom.png",
|
"mesecons_delayer_bottom.png",
|
||||||
@ -127,33 +132,17 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
|||||||
"mesecons_delayer_sides_on.png",
|
"mesecons_delayer_sides_on.png",
|
||||||
"mesecons_delayer_sides_on.png"
|
"mesecons_delayer_sides_on.png"
|
||||||
},
|
},
|
||||||
walkable = true,
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
|
|
||||||
},
|
|
||||||
node_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = boxes
|
|
||||||
},
|
|
||||||
groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1},
|
groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1},
|
||||||
paramtype = "light",
|
on_punch = function(pos, node, puncher)
|
||||||
paramtype2 = "facedir",
|
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||||
sunlight_propagates = true,
|
return
|
||||||
is_ground_content = true,
|
|
||||||
drop = 'mesecons_delayer:delayer_off_1',
|
|
||||||
on_punch = function (pos, node)
|
|
||||||
if node.name=="mesecons_delayer:delayer_on_1" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_2", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_on_2" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_3", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_on_3" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_4", param2=node.param2})
|
|
||||||
elseif node.name=="mesecons_delayer:delayer_on_4" then
|
|
||||||
minetest.swap_node(pos, {name = "mesecons_delayer:delayer_on_1", param2=node.param2})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
minetest.swap_node(pos, {
|
||||||
|
name = "mesecons_delayer:delayer_on_"..tostring(i % 4 + 1),
|
||||||
|
param2 = node.param2
|
||||||
|
})
|
||||||
end,
|
end,
|
||||||
delayer_time = delaytime,
|
|
||||||
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
|
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
|
||||||
mesecons = {
|
mesecons = {
|
||||||
receptor =
|
receptor =
|
||||||
@ -166,8 +155,13 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
|||||||
rules = delayer_get_input_rules,
|
rules = delayer_get_input_rules,
|
||||||
action_off = delayer_deactivate
|
action_off = delayer_deactivate
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
}
|
||||||
|
for k, v in pairs(def) do
|
||||||
|
on_state[k] = on_state[k] or v
|
||||||
|
end
|
||||||
|
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), on_state)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 562 B After Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 446 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 630 B After Width: | Height: | Size: 538 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 181 B |
@ -1,6 +1,11 @@
|
|||||||
The node detector is a receptor. It changes its state when either any node
|
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.
|
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
|
It can also receive digiline signals. For example, you can send
|
||||||
respond with the detected nodename or you can send any other string and it will
|
<code>{distance=4, scanname="default:dirt"}</code>
|
||||||
set this string as the node to scan for.
|
to set distance to 4 and scan for dirt. You can omit either parameter.
|
||||||
|
There is also a command parameter: <code>{command="get"}</code> will respond
|
||||||
|
with the detected nodename and <code>{command="scan"}</code> will respond with
|
||||||
|
a boolean using the distance and nodename of the detector.
|
||||||
Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt.
|
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 After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 7.3 KiB |
@ -1,3 +1,5 @@
|
|||||||
The object detector is a receptor. It changes its state when a player approaches.
|
The object detector is a receptor. It changes its state when a player approaches.
|
||||||
Right-click it to set a name to scan for.
|
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.
|
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 After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 7.1 KiB |
@ -5,15 +5,18 @@ local GET_COMMAND = "GET"
|
|||||||
-- The radius can be specified in mesecons/settings.lua
|
-- The radius can be specified in mesecons/settings.lua
|
||||||
|
|
||||||
local function object_detector_make_formspec(pos)
|
local function object_detector_make_formspec(pos)
|
||||||
minetest.get_meta(pos):set_string("formspec", "size[9,2.5]" ..
|
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}]"..
|
"field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]"..
|
||||||
"field[0.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]")
|
"button_exit[7,0.75;2,3;;Save]")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function object_detector_on_receive_fields(pos, _, fields)
|
local function object_detector_on_receive_fields(pos, formname, fields, sender)
|
||||||
if not fields.scanname or not fields.digiline_channel then return end
|
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 meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_string("scanname", fields.scanname)
|
meta:set_string("scanname", fields.scanname)
|
||||||
meta:set_string("digiline_channel", fields.digiline_channel)
|
meta:set_string("digiline_channel", fields.digiline_channel)
|
||||||
@ -28,14 +31,17 @@ local function object_detector_scan(pos)
|
|||||||
if next(objs) == nil then return false end
|
if next(objs) == nil then return false end
|
||||||
|
|
||||||
local scanname = minetest.get_meta(pos):get_string("scanname")
|
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 == ""
|
local every_player = scanname == ""
|
||||||
for _, obj in pairs(objs) do
|
for _, obj in pairs(objs) do
|
||||||
-- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
|
-- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
|
||||||
local foundname = obj:get_player_name()
|
local foundname = obj:get_player_name()
|
||||||
|
|
||||||
if foundname ~= "" then
|
if foundname ~= "" then
|
||||||
-- return true if scanning for any player or if specific playername was detected
|
if every_player or scan_for[foundname] then
|
||||||
if scanname == "" or foundname == scanname then
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -60,6 +66,7 @@ local object_detector_digiline = {
|
|||||||
minetest.register_node("mesecons_detector:object_detector_off", {
|
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"},
|
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",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = true,
|
walkable = true,
|
||||||
groups = {cracky=3},
|
groups = {cracky=3},
|
||||||
description="Player Detector",
|
description="Player Detector",
|
||||||
@ -70,12 +77,14 @@ minetest.register_node("mesecons_detector:object_detector_off", {
|
|||||||
on_construct = object_detector_make_formspec,
|
on_construct = object_detector_make_formspec,
|
||||||
on_receive_fields = object_detector_on_receive_fields,
|
on_receive_fields = object_detector_on_receive_fields,
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
digiline = object_detector_digiline
|
digiline = object_detector_digiline,
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_detector:object_detector_on", {
|
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"},
|
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",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = true,
|
walkable = true,
|
||||||
groups = {cracky=3,not_in_creative_inventory=1},
|
groups = {cracky=3,not_in_creative_inventory=1},
|
||||||
drop = 'mesecons_detector:object_detector_off',
|
drop = 'mesecons_detector:object_detector_off',
|
||||||
@ -86,7 +95,8 @@ minetest.register_node("mesecons_detector:object_detector_on", {
|
|||||||
on_construct = object_detector_make_formspec,
|
on_construct = object_detector_make_formspec,
|
||||||
on_receive_fields = object_detector_on_receive_fields,
|
on_receive_fields = object_detector_on_receive_fields,
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
digiline = object_detector_digiline
|
digiline = object_detector_digiline,
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
@ -98,6 +108,15 @@ 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({
|
minetest.register_abm({
|
||||||
nodenames = {"mesecons_detector:object_detector_off"},
|
nodenames = {"mesecons_detector:object_detector_off"},
|
||||||
interval = 1,
|
interval = 1,
|
||||||
@ -128,17 +147,23 @@ minetest.register_abm({
|
|||||||
-- Detects the node in front of it
|
-- Detects the node in front of it
|
||||||
|
|
||||||
local function node_detector_make_formspec(pos)
|
local function node_detector_make_formspec(pos)
|
||||||
minetest.get_meta(pos):set_string("formspec", "size[9,2.5]" ..
|
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, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]"..
|
||||||
"field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
|
"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}]"..
|
||||||
"button_exit[7,0.75;2,3;;Save]")
|
"button_exit[7,0.75;2,3;;Save]")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function node_detector_on_receive_fields(pos, _, fields)
|
local function node_detector_on_receive_fields(pos, fieldname, fields, sender)
|
||||||
if not fields.scanname or not fields.digiline_channel then return end
|
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 meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
meta:set_string("scanname", fields.scanname)
|
meta:set_string("scanname", fields.scanname)
|
||||||
|
meta:set_string("distance", fields.distance or "0")
|
||||||
meta:set_string("digiline_channel", fields.digiline_channel)
|
meta:set_string("digiline_channel", fields.digiline_channel)
|
||||||
node_detector_make_formspec(pos)
|
node_detector_make_formspec(pos)
|
||||||
end
|
end
|
||||||
@ -148,32 +173,66 @@ local function node_detector_scan(pos)
|
|||||||
local node = minetest.get_node_or_nil(pos)
|
local node = minetest.get_node_or_nil(pos)
|
||||||
if not node then return end
|
if not node then return end
|
||||||
|
|
||||||
|
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(
|
local frontname = minetest.get_node(
|
||||||
vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
|
||||||
).name
|
).name
|
||||||
local scanname = minetest.get_meta(pos):get_string("scanname")
|
local scanname = meta:get_string("scanname")
|
||||||
|
|
||||||
return (frontname == scanname) or
|
return (frontname == scanname) or
|
||||||
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
|
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function node_detector_send_node_name(pos, node, channel, meta)
|
||||||
|
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 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)
|
||||||
|
end
|
||||||
|
|
||||||
-- set player name when receiving a digiline signal on a specific channel
|
-- set player name when receiving a digiline signal on a specific channel
|
||||||
local node_detector_digiline = {
|
local node_detector_digiline = {
|
||||||
effector = {
|
effector = {
|
||||||
action = function(pos, node, channel, msg)
|
action = function(pos, node, channel, msg)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
|
|
||||||
if channel ~= meta:get_string("digiline_channel") then return end
|
if channel ~= meta:get_string("digiline_channel") then return end
|
||||||
|
|
||||||
|
if type(msg) == "table" then
|
||||||
|
if msg.distance or msg.scanname then
|
||||||
|
if msg.distance then
|
||||||
|
meta:set_string("distance", msg.distance)
|
||||||
|
end
|
||||||
|
if msg.scanname then
|
||||||
|
meta:set_string("scanname", msg.scanname)
|
||||||
|
end
|
||||||
|
node_detector_make_formspec(pos)
|
||||||
|
end
|
||||||
|
if msg.command == "get" then
|
||||||
|
node_detector_send_node_name(pos, node, channel, meta)
|
||||||
|
elseif msg.command == "scan" then
|
||||||
|
local result = node_detector_scan(pos)
|
||||||
|
digiline:receptor_send(pos, digiline.rules.default, channel, result)
|
||||||
|
end
|
||||||
|
else
|
||||||
if msg == GET_COMMAND then
|
if msg == GET_COMMAND then
|
||||||
local nodename = minetest.get_node(
|
node_detector_send_node_name(pos, node, channel, meta)
|
||||||
vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
|
||||||
).name
|
|
||||||
|
|
||||||
digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
|
|
||||||
else
|
else
|
||||||
meta:set_string("scanname", msg)
|
meta:set_string("scanname", msg)
|
||||||
node_detector_make_formspec(pos)
|
node_detector_make_formspec(pos)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
receptor = {}
|
receptor = {}
|
||||||
@ -200,6 +259,7 @@ 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"},
|
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",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = true,
|
walkable = true,
|
||||||
groups = {cracky=3},
|
groups = {cracky=3},
|
||||||
description="Node Detector",
|
description="Node Detector",
|
||||||
@ -208,15 +268,16 @@ minetest.register_node("mesecons_detector:node_detector_off", {
|
|||||||
}},
|
}},
|
||||||
on_construct = node_detector_make_formspec,
|
on_construct = node_detector_make_formspec,
|
||||||
on_receive_fields = node_detector_on_receive_fields,
|
on_receive_fields = node_detector_on_receive_fields,
|
||||||
after_place_node = after_place_node_detector,
|
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
digiline = node_detector_digiline
|
digiline = node_detector_digiline,
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_detector:node_detector_on", {
|
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"},
|
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",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = true,
|
walkable = true,
|
||||||
groups = {cracky=3,not_in_creative_inventory=1},
|
groups = {cracky=3,not_in_creative_inventory=1},
|
||||||
drop = 'mesecons_detector:node_detector_off',
|
drop = 'mesecons_detector:node_detector_off',
|
||||||
@ -225,9 +286,9 @@ minetest.register_node("mesecons_detector:node_detector_on", {
|
|||||||
}},
|
}},
|
||||||
on_construct = node_detector_make_formspec,
|
on_construct = node_detector_make_formspec,
|
||||||
on_receive_fields = node_detector_on_receive_fields,
|
on_receive_fields = node_detector_on_receive_fields,
|
||||||
after_place_node = after_place_node_detector,
|
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
digiline = node_detector_digiline
|
digiline = node_detector_digiline,
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
@ -239,6 +300,15 @@ 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({
|
minetest.register_abm({
|
||||||
nodenames = {"mesecons_detector:node_detector_off"},
|
nodenames = {"mesecons_detector:node_detector_off"},
|
||||||
interval = 1,
|
interval = 1,
|
||||||
|
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 640 B |
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 687 B |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 655 B |
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 693 B |
@ -1,12 +1,15 @@
|
|||||||
|
local screwdriver_exists = minetest.global_exists("screwdriver")
|
||||||
|
|
||||||
local corner_nodebox = {
|
local corner_nodebox = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
-- ±0.001 is to prevent z-fighting
|
||||||
fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 },
|
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}}
|
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, 3/32}}
|
||||||
}
|
}
|
||||||
|
|
||||||
local corner_selectionbox = {
|
local corner_selectionbox = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = { -16/32-0.001, -18/32, -16/32, 5/32, -12/32, 5/32 },
|
fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
local corner_get_rules = function (node)
|
local corner_get_rules = function (node)
|
||||||
@ -33,23 +36,27 @@ minetest.register_node("mesecons_extrawires:corner_on", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = corner_selectionbox,
|
selection_box = corner_selectionbox,
|
||||||
node_box = corner_nodebox,
|
node_box = corner_nodebox,
|
||||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||||
drop = "mesecons_extrawires:corner_off",
|
drop = "mesecons_extrawires:corner_off",
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {conductor =
|
mesecons = {conductor =
|
||||||
{
|
{
|
||||||
state = mesecon.state.on,
|
state = mesecon.state.on,
|
||||||
rules = corner_get_rules,
|
rules = corner_get_rules,
|
||||||
offstate = "mesecons_extrawires:corner_off"
|
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", {
|
minetest.register_node("mesecons_extrawires:corner_off", {
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
description = "Mesecon Corner",
|
description = "Insulated Mesecon Corner",
|
||||||
tiles = {
|
tiles = {
|
||||||
"jeija_insulated_wire_curved_tb_off.png",
|
"jeija_insulated_wire_curved_tb_off.png",
|
||||||
"jeija_insulated_wire_curved_tb_off.png^[transformR270",
|
"jeija_insulated_wire_curved_tb_off.png^[transformR270",
|
||||||
@ -60,17 +67,21 @@ minetest.register_node("mesecons_extrawires:corner_off", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = corner_selectionbox,
|
selection_box = corner_selectionbox,
|
||||||
node_box = corner_nodebox,
|
node_box = corner_nodebox,
|
||||||
groups = {dig_immediate = 3},
|
groups = {dig_immediate = 3},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {conductor =
|
mesecons = {conductor =
|
||||||
{
|
{
|
||||||
state = mesecon.state.off,
|
state = mesecon.state.off,
|
||||||
rules = corner_get_rules,
|
rules = corner_get_rules,
|
||||||
onstate = "mesecons_extrawires:corner_on"
|
onstate = "mesecons_extrawires:corner_on"
|
||||||
}}
|
}},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
|
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
function crossover_get_rules(node)
|
local function crossover_get_rules(node)
|
||||||
return {
|
return {
|
||||||
{--first wire
|
{--first wire
|
||||||
{x=-1,y=0,z=0},
|
{x=-1,y=0,z=0},
|
||||||
@ -19,143 +19,110 @@ local crossover_states = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
minetest.register_node("mesecons_extrawires:crossover_off", {
|
minetest.register_node("mesecons_extrawires:crossover_off", {
|
||||||
description = "Insulated Crossover",
|
description = "Insulated Mesecon Crossover",
|
||||||
drawtype = "nodebox",
|
drawtype = "mesh",
|
||||||
|
mesh = "mesecons_extrawires_crossover.b3d",
|
||||||
tiles = {
|
tiles = {
|
||||||
"jeija_insulated_wire_crossing_tb_off.png",
|
"jeija_insulated_wire_ends_off.png",
|
||||||
"jeija_insulated_wire_crossing_tb_off.png",
|
"jeija_insulated_wire_sides_off.png",
|
||||||
|
"jeija_insulated_wire_sides_off.png",
|
||||||
"jeija_insulated_wire_ends_off.png"
|
"jeija_insulated_wire_ends_off.png"
|
||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
stack_max = 99,
|
stack_max = 99,
|
||||||
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}},
|
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||||
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},
|
groups = {dig_immediate=3, mesecon=3},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {
|
mesecons = {
|
||||||
conductor = {
|
conductor = {
|
||||||
states = crossover_states,
|
states = crossover_states,
|
||||||
rules = crossover_get_rules(),
|
rules = crossover_get_rules(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_extrawires:crossover_01", {
|
minetest.register_node("mesecons_extrawires:crossover_01", {
|
||||||
description = "You hacker you!",
|
description = "You hacker you!",
|
||||||
drop = "mesecons_extrawires:crossover_off",
|
drop = "mesecons_extrawires:crossover_off",
|
||||||
drawtype = "nodebox",
|
drawtype = "mesh",
|
||||||
|
mesh = "mesecons_extrawires_crossover.b3d",
|
||||||
tiles = {
|
tiles = {
|
||||||
"jeija_insulated_wire_crossing_tb_01.png",
|
"jeija_insulated_wire_ends_on.png",
|
||||||
"jeija_insulated_wire_crossing_tb_01.png",
|
"jeija_insulated_wire_sides_on.png",
|
||||||
"jeija_insulated_wire_ends_01x.png",
|
"jeija_insulated_wire_sides_off.png",
|
||||||
"jeija_insulated_wire_ends_01x.png",
|
"jeija_insulated_wire_ends_off.png"
|
||||||
"jeija_insulated_wire_ends_01z.png",
|
|
||||||
"jeija_insulated_wire_ends_01z.png"
|
|
||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
stack_max = 99,
|
stack_max = 99,
|
||||||
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}},
|
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||||
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},
|
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {
|
mesecons = {
|
||||||
conductor = {
|
conductor = {
|
||||||
states = crossover_states,
|
states = crossover_states,
|
||||||
rules = crossover_get_rules(),
|
rules = crossover_get_rules(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_extrawires:crossover_10", {
|
minetest.register_node("mesecons_extrawires:crossover_10", {
|
||||||
description = "You hacker you!",
|
description = "You hacker you!",
|
||||||
drop = "mesecons_extrawires:crossover_off",
|
drop = "mesecons_extrawires:crossover_off",
|
||||||
drawtype = "nodebox",
|
drawtype = "mesh",
|
||||||
|
mesh = "mesecons_extrawires_crossover.b3d",
|
||||||
tiles = {
|
tiles = {
|
||||||
"jeija_insulated_wire_crossing_tb_10.png",
|
"jeija_insulated_wire_ends_off.png",
|
||||||
"jeija_insulated_wire_crossing_tb_10.png",
|
"jeija_insulated_wire_sides_off.png",
|
||||||
"jeija_insulated_wire_ends_10x.png",
|
"jeija_insulated_wire_sides_on.png",
|
||||||
"jeija_insulated_wire_ends_10x.png",
|
"jeija_insulated_wire_ends_on.png"
|
||||||
"jeija_insulated_wire_ends_10z.png",
|
|
||||||
"jeija_insulated_wire_ends_10z.png"
|
|
||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
stack_max = 99,
|
stack_max = 99,
|
||||||
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}},
|
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||||
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},
|
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {
|
mesecons = {
|
||||||
conductor = {
|
conductor = {
|
||||||
states = crossover_states,
|
states = crossover_states,
|
||||||
rules = crossover_get_rules(),
|
rules = crossover_get_rules(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mesecons_extrawires:crossover_on", {
|
minetest.register_node("mesecons_extrawires:crossover_on", {
|
||||||
description = "You hacker you!",
|
description = "You hacker you!",
|
||||||
drop = "mesecons_extrawires:crossover_off",
|
drop = "mesecons_extrawires:crossover_off",
|
||||||
drawtype = "nodebox",
|
drawtype = "mesh",
|
||||||
|
mesh = "mesecons_extrawires_crossover.b3d",
|
||||||
tiles = {
|
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_ends_on.png",
|
||||||
|
"jeija_insulated_wire_sides_on.png",
|
||||||
|
"jeija_insulated_wire_sides_on.png",
|
||||||
"jeija_insulated_wire_ends_on.png"
|
"jeija_insulated_wire_ends_on.png"
|
||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
stack_max = 99,
|
stack_max = 99,
|
||||||
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}},
|
selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}},
|
||||||
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},
|
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {
|
mesecons = {
|
||||||
conductor = {
|
conductor = {
|
||||||
states = crossover_states,
|
states = crossover_states,
|
||||||
rules = crossover_get_rules(),
|
rules = crossover_get_rules(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
default
|
default
|
||||||
mesecons
|
mesecons
|
||||||
|
screwdriver?
|
||||||
|
@ -1 +1 @@
|
|||||||
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.
|
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 After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.9 KiB |
@ -1 +1 @@
|
|||||||
Insulated crossing are conductors that conduct two signals between the opposing sides, the signals are insulated to each other.
|
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 After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.7 KiB |
@ -1 +1 @@
|
|||||||
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
|
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 After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.5 KiB |
@ -1 +1 @@
|
|||||||
Insulated T-Junctions are conductors that only conduct between the inputs (also not up or down).
|
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 After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.9 KiB |
@ -1 +1 @@
|
|||||||
Vertical Mesecons only conduct up and down. Plates appear at the ends, at that place they also conduct to the side.
|
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 After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.9 KiB |
@ -26,7 +26,8 @@ local powered_def = mesecon.mergetable(minetest.registered_nodes["default:mese"]
|
|||||||
offstate = "default:mese",
|
offstate = "default:mese",
|
||||||
rules = mesewire_rules
|
rules = mesewire_rules
|
||||||
}},
|
}},
|
||||||
groups = {cracky = 1, not_in_creative_inventory = 1}
|
groups = {cracky = 1, not_in_creative_inventory = 1},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
})
|
})
|
||||||
|
|
||||||
for i, v in pairs(powered_def.tiles) do
|
for i, v in pairs(powered_def.tiles) do
|
||||||
|
BIN
mesecons_extrawires/models/mesecons_extrawires_crossover.b3d
Normal file
BIN
mesecons_extrawires/src/mesecons_extrawires_crossover.blend
Normal file
@ -1,12 +1,15 @@
|
|||||||
|
local screwdriver_exists = minetest.global_exists("screwdriver")
|
||||||
|
|
||||||
local tjunction_nodebox = {
|
local tjunction_nodebox = {
|
||||||
type = "fixed",
|
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 },
|
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},}
|
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, -3/32},}
|
||||||
}
|
}
|
||||||
|
|
||||||
local tjunction_selectionbox = {
|
local tjunction_selectionbox = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = { -16/32-0.001, -18/32, -16/32, 16/32+0.001, -12/32, 7/32 },
|
fixed = { -16/32, -16/32, -16/32, 16/32, -12/32, 7/32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
local tjunction_get_rules = function (node)
|
local tjunction_get_rules = function (node)
|
||||||
@ -34,23 +37,27 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = tjunction_selectionbox,
|
selection_box = tjunction_selectionbox,
|
||||||
node_box = tjunction_nodebox,
|
node_box = tjunction_nodebox,
|
||||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||||
drop = "mesecons_extrawires:tjunction_off",
|
drop = "mesecons_extrawires:tjunction_off",
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {conductor =
|
mesecons = {conductor =
|
||||||
{
|
{
|
||||||
state = mesecon.state.on,
|
state = mesecon.state.on,
|
||||||
rules = tjunction_get_rules,
|
rules = tjunction_get_rules,
|
||||||
offstate = "mesecons_extrawires:tjunction_off"
|
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", {
|
minetest.register_node("mesecons_extrawires:tjunction_off", {
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
description = "T-junction",
|
description = "Insulated Mesecon T-junction",
|
||||||
tiles = {
|
tiles = {
|
||||||
"jeija_insulated_wire_tjunction_tb_off.png",
|
"jeija_insulated_wire_tjunction_tb_off.png",
|
||||||
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180",
|
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180",
|
||||||
@ -61,17 +68,21 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
|
|||||||
},
|
},
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
|
is_ground_content = false,
|
||||||
walkable = false,
|
walkable = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = tjunction_selectionbox,
|
selection_box = tjunction_selectionbox,
|
||||||
node_box = tjunction_nodebox,
|
node_box = tjunction_nodebox,
|
||||||
groups = {dig_immediate = 3},
|
groups = {dig_immediate = 3},
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
mesecons = {conductor =
|
mesecons = {conductor =
|
||||||
{
|
{
|
||||||
state = mesecon.state.off,
|
state = mesecon.state.off,
|
||||||
rules = tjunction_get_rules,
|
rules = tjunction_get_rules,
|
||||||
onstate = "mesecons_extrawires:tjunction_on"
|
onstate = "mesecons_extrawires:tjunction_on"
|
||||||
}}
|
}},
|
||||||
|
on_blast = mesecon.on_blastnode,
|
||||||
|
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -77,17 +77,19 @@ end
|
|||||||
|
|
||||||
-- Vertical wire
|
-- Vertical wire
|
||||||
mesecon.register_node("mesecons_extrawires:vertical", {
|
mesecon.register_node("mesecons_extrawires:vertical", {
|
||||||
description = "Vertical mesecon",
|
description = "Vertical Mesecon",
|
||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
walkable = false,
|
walkable = false,
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
selection_box = vertical_box,
|
selection_box = vertical_box,
|
||||||
node_box = vertical_box,
|
node_box = vertical_box,
|
||||||
is_vertical_conductor = true,
|
is_vertical_conductor = true,
|
||||||
drop = "mesecons_extrawires:vertical_off",
|
drop = "mesecons_extrawires:vertical_off",
|
||||||
after_place_node = vertical_update,
|
after_place_node = vertical_update,
|
||||||
after_dig_node = vertical_update
|
after_dig_node = vertical_update,
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
},{
|
},{
|
||||||
tiles = {"mesecons_wire_off.png"},
|
tiles = {"mesecons_wire_off.png"},
|
||||||
groups = {dig_immediate=3},
|
groups = {dig_immediate=3},
|
||||||
@ -112,6 +114,7 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
|
|||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
walkable = false,
|
walkable = false,
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
groups = {dig_immediate=3, not_in_creative_inventory=1},
|
groups = {dig_immediate=3, not_in_creative_inventory=1},
|
||||||
selection_box = top_box,
|
selection_box = top_box,
|
||||||
@ -119,7 +122,8 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
|
|||||||
is_vertical_conductor = true,
|
is_vertical_conductor = true,
|
||||||
drop = "mesecons_extrawires:vertical_off",
|
drop = "mesecons_extrawires:vertical_off",
|
||||||
after_place_node = vertical_update,
|
after_place_node = vertical_update,
|
||||||
after_dig_node = vertical_update
|
after_dig_node = vertical_update,
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
},{
|
},{
|
||||||
tiles = {"mesecons_wire_off.png"},
|
tiles = {"mesecons_wire_off.png"},
|
||||||
mesecons = {conductor = {
|
mesecons = {conductor = {
|
||||||
@ -142,6 +146,7 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
|
|||||||
drawtype = "nodebox",
|
drawtype = "nodebox",
|
||||||
walkable = false,
|
walkable = false,
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
is_ground_content = false,
|
||||||
sunlight_propagates = true,
|
sunlight_propagates = true,
|
||||||
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
||||||
selection_box = bottom_box,
|
selection_box = bottom_box,
|
||||||
@ -149,7 +154,8 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
|
|||||||
is_vertical_conductor = true,
|
is_vertical_conductor = true,
|
||||||
drop = "mesecons_extrawires:vertical_off",
|
drop = "mesecons_extrawires:vertical_off",
|
||||||
after_place_node = vertical_update,
|
after_place_node = vertical_update,
|
||||||
after_dig_node = vertical_update
|
after_dig_node = vertical_update,
|
||||||
|
sounds = default.node_sound_defaults(),
|
||||||
},{
|
},{
|
||||||
tiles = {"mesecons_wire_off.png"},
|
tiles = {"mesecons_wire_off.png"},
|
||||||
mesecons = {conductor = {
|
mesecons = {conductor = {
|
||||||
|
2
mesecons_fpga/depends.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mesecons
|
||||||
|
screwdriver?
|
6
mesecons_fpga/doc/fpga/description.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
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>
|
BIN
mesecons_fpga/doc/fpga/preview.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
mesecons_fpga/doc/fpga/recipe.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
3
mesecons_fpga/doc/programmer/description.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
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.
|
BIN
mesecons_fpga/doc/programmer/preview.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
mesecons_fpga/doc/programmer/recipe.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
455
mesecons_fpga/init.lua
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
local plg = {}
|
||||||
|
plg.rules = {}
|
||||||
|
-- per-player formspec positions
|
||||||
|
plg.open_formspecs = {}
|
||||||
|
|
||||||
|
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("infotext", "FPGA")
|
||||||
|
end,
|
||||||
|
on_rightclick = function(pos, node, clicker)
|
||||||
|
if not minetest.is_player(clicker) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local name = clicker:get_player_name()
|
||||||
|
-- Erase formspecs of old FPGAs
|
||||||
|
meta:set_string("formspec", "")
|
||||||
|
|
||||||
|
plg.open_formspecs[name] = pos
|
||||||
|
local is = lcore.deserialize(meta:get_string("instr"))
|
||||||
|
minetest.show_formspec(name, "mesecons:fpga", plg.to_formspec_string(is, nil))
|
||||||
|
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])
|
||||||
|
for name, open_pos in pairs(plg.open_formspecs) do
|
||||||
|
if vector.equals(pos, open_pos) then
|
||||||
|
minetest.close_formspec(name, "mesecons:fpga")
|
||||||
|
plg.open_formspecs[name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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_meta(pos, instr)
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
plg.to_formspec_string = function(is, err)
|
||||||
|
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 selected = 0
|
||||||
|
local titles = { " " }
|
||||||
|
for i, data in ipairs(lcore.get_operations()) do
|
||||||
|
titles[i + 1] = data.fs_name
|
||||||
|
if val == data.gate then
|
||||||
|
selected = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ("dropdown[%f,%f;1.125,0.5;%s;%s;%i]"):format(
|
||||||
|
x, y, name, table.concat(titles, ","), selected)
|
||||||
|
end
|
||||||
|
local s = "size[9,9]"..
|
||||||
|
"label[3.4,-0.15;FPGA gate configuration]"..
|
||||||
|
"button[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
|
||||||
|
if err then
|
||||||
|
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
|
||||||
|
s = s .. 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
|
||||||
|
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)
|
||||||
|
for i, data in ipairs(lcore.get_operations()) do
|
||||||
|
if data.fs_name == s then
|
||||||
|
return data.gate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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_meta = function(pos, is)
|
||||||
|
if type(is) == "string" then -- serialized string
|
||||||
|
is = lcore.deserialize(is)
|
||||||
|
end
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
|
||||||
|
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")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- reset ports and run programmed logic
|
||||||
|
plg.setports(pos, false, false, false, false)
|
||||||
|
plg.update(pos)
|
||||||
|
|
||||||
|
-- Refresh open formspecs
|
||||||
|
local form = plg.to_formspec_string(is, err)
|
||||||
|
for name, open_pos in pairs(plg.open_formspecs) do
|
||||||
|
if vector.equals(pos, open_pos) then
|
||||||
|
minetest.show_formspec(name, "mesecons:fpga", form)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return err
|
||||||
|
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_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
|
||||||
|
if formname ~= "mesecons:fpga" or fields.quit then
|
||||||
|
plg.open_formspecs[player_name] = nil -- potential garbage
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not fields.program then
|
||||||
|
return -- we only care when the user clicks "Program"
|
||||||
|
end
|
||||||
|
local pos = plg.open_formspecs[player_name]
|
||||||
|
if minetest.is_protected(pos, player_name) then
|
||||||
|
minetest.record_protection_violation(pos, player_name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local is = plg.from_formspec_fields(fields)
|
||||||
|
|
||||||
|
meta:set_string("instr", lcore.serialize(is))
|
||||||
|
local err = plg.update_meta(pos, is)
|
||||||
|
|
||||||
|
if not err then
|
||||||
|
plg.open_formspecs[player_name] = nil
|
||||||
|
-- Close on success
|
||||||
|
minetest.close_formspec(player_name, "mesecons:fpga")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
plg.open_formspecs[player:get_player_name()] = nil
|
||||||
|
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'},
|
||||||
|
}
|
||||||
|
})
|
222
mesecons_fpga/logic.lua
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
|
||||||
|
local lg = {}
|
||||||
|
|
||||||
|
local operations = {
|
||||||
|
-- table index: Index in the formspec dropdown
|
||||||
|
-- gate: Internal name
|
||||||
|
-- short: Serialized form, single character
|
||||||
|
-- fs_name: Display name, padded to 4 characters
|
||||||
|
-- func: Function that applies the operation
|
||||||
|
-- unary: Whether this gate only has one input
|
||||||
|
{ gate = "and", short = "&", fs_name = " AND", func = function(a, b) return a and b end },
|
||||||
|
{ gate = "or", short = "|", fs_name = " OR", func = function(a, b) return a or b end },
|
||||||
|
{ gate = "not", short = "~", fs_name = " NOT", func = function(a, b) return not b end, unary = true },
|
||||||
|
{ gate = "xor", short = "^", fs_name = " XOR", func = function(a, b) return a ~= b end },
|
||||||
|
{ gate = "nand", short = "?", fs_name = "NAND", func = function(a, b) return not (a and b) end },
|
||||||
|
{ gate = "buf", short = "_", fs_name = " =", func = function(a, b) return b end, unary = true },
|
||||||
|
{ gate = "xnor", short = "=", fs_name = "XNOR", func = function(a, b) return a == b end },
|
||||||
|
{ gate = "nor", short = "!", fs_name = " NOR", func = function(a, b) return not (a or b) end },
|
||||||
|
}
|
||||||
|
|
||||||
|
lg.get_operations = function()
|
||||||
|
return operations
|
||||||
|
end
|
||||||
|
|
||||||
|
-- (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
|
||||||
|
-- Serialize actions (gates) from eg. "and" to "&"
|
||||||
|
local function _action(action)
|
||||||
|
for i, data in ipairs(operations) do
|
||||||
|
if data.gate == action then
|
||||||
|
return data.short
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return " "
|
||||||
|
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
|
||||||
|
-- Deserialize actions (gates) from eg. "&" to "and"
|
||||||
|
local function _action(action)
|
||||||
|
for i, data in ipairs(operations) do
|
||||||
|
if data.short == action then
|
||||||
|
return data.gate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- nil
|
||||||
|
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]
|
||||||
|
|
||||||
|
local gate_data
|
||||||
|
for j, data in ipairs(operations) do
|
||||||
|
if data.gate == elem.action then
|
||||||
|
gate_data = data
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check for completeness
|
||||||
|
if not gate_data then
|
||||||
|
return {i = i, msg = "Gate type is required"}
|
||||||
|
elseif gate_data.unary then
|
||||||
|
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then
|
||||||
|
return {i = i, msg = "Second operand (only) and destination are required"}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
|
||||||
|
return {i = i, msg = "Operands and destination are 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)
|
||||||
|
for i, data in ipairs(operations) do
|
||||||
|
if data.gate == s then
|
||||||
|
return data.func(v1, v2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false -- unknown gate
|
||||||
|
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
|
BIN
mesecons_fpga/textures/jeija_fpga_programmer.png
Normal file
After Width: | Height: | Size: 256 B |
BIN
mesecons_fpga/textures/jeija_fpga_sides.png
Normal file
After Width: | Height: | Size: 480 B |