Compare commits
18 Commits
v1.2.1
...
e1cffdedbf
Author | SHA1 | Date | |
---|---|---|---|
e1cffdedbf | |||
d3aedd2b98 | |||
68c1729990 | |||
9b58f8db29 | |||
7784b13da5 | |||
0dd530312b | |||
e78bbd6f98 | |||
bfd952b51a | |||
b7873e8e02 | |||
d6b2a39c99 | |||
1b54011b68 | |||
15e743629e | |||
1bf862f932 | |||
1a9704f184 | |||
8baa789eb1 | |||
b0158f5674 | |||
073c92d487 | |||
737f366741 |
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
*~
|
||||
*.patch
|
||||
*.diff
|
||||
|
@ -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)
|
||||
mesecon.queue.funcs[name] = func
|
||||
The ActionQueue holds functions and actions.
|
||||
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
|
||||
|
||||
-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten
|
||||
-- use overwritecheck nil to never overwrite, but just add the event to the queue
|
||||
-- priority specifies the order actions are executed within one globalstep, highest first
|
||||
-- should be between 0 and 1
|
||||
function mesecon.queue:add_action(pos, func, params, time, overwritecheck, priority)
|
||||
function queue:add_action(pos, func, params, time, overwritecheck, priority)
|
||||
-- Create Action Table:
|
||||
time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution
|
||||
priority = priority or 1
|
||||
local action = { pos=mesecon.tablecopy(pos),
|
||||
local action = {
|
||||
pos = mesecon.tablecopy(pos),
|
||||
func = func,
|
||||
params = mesecon.tablecopy(params or {}),
|
||||
time = time,
|
||||
owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
|
||||
priority=priority}
|
||||
priority = priority
|
||||
}
|
||||
|
||||
local toremove = nil
|
||||
-- Otherwise, add the action to the queue
|
||||
if overwritecheck then -- check if old action has to be overwritten / removed:
|
||||
for i, ac in ipairs(mesecon.queue.actions) do
|
||||
if(vector.equals(pos, ac.pos)
|
||||
and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
|
||||
toremove = i
|
||||
-- check if old action has to be overwritten / removed:
|
||||
if overwritecheck then
|
||||
for i, ac in ipairs(queue.actions) do
|
||||
if vector.equals(pos, ac.pos)
|
||||
and mesecon.cmpAny(overwritecheck, ac.owcheck) then
|
||||
-- remove the old action
|
||||
table.remove(queue.actions, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (toremove ~= nil) then
|
||||
table.remove(mesecon.queue.actions, toremove)
|
||||
end
|
||||
|
||||
table.insert(mesecon.queue.actions, action)
|
||||
table.insert(queue.actions, action)
|
||||
end
|
||||
|
||||
-- execute the stored functions on a globalstep
|
||||
-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function
|
||||
-- this makes sure that resuming mesecons circuits when restarting minetest works fine
|
||||
-- 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
|
||||
-- start to be execute by 5 seconds
|
||||
local get_highest_priority = function (actions)
|
||||
local highestp = -1
|
||||
local highesti
|
||||
for i, ac in ipairs(actions) do
|
||||
if ac.priority > highestp then
|
||||
highestp = ac.priority
|
||||
highesti = i
|
||||
end
|
||||
end
|
||||
-- start to be execute by 4 seconds
|
||||
|
||||
return highesti
|
||||
end
|
||||
|
||||
local m_time = 0
|
||||
local resumetime = mesecon.setting("resumetime", 4)
|
||||
minetest.register_globalstep(function (dtime)
|
||||
m_time = m_time + dtime
|
||||
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
|
||||
-- after starting the server before processing the ActionQueue, don't set this too low
|
||||
if (m_time < resumetime) then return end
|
||||
local actions = mesecon.tablecopy(mesecon.queue.actions)
|
||||
local function globalstep_func(dtime)
|
||||
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 = {}
|
||||
|
||||
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
|
||||
for _, ac in ipairs(actions) do
|
||||
if ac.time > 0 then
|
||||
ac.time = ac.time - dtime -- executed later
|
||||
table.insert(mesecon.queue.actions, ac)
|
||||
-- action ac is to be executed later
|
||||
-- ~> insert into queue.actions
|
||||
ac.time = ac.time - dtime
|
||||
table.insert(queue.actions, ac)
|
||||
else
|
||||
-- action ac is to be executed now
|
||||
-- ~> insert into actions_now
|
||||
table.insert(actions_now, ac)
|
||||
end
|
||||
end
|
||||
|
||||
while(#actions_now > 0) do -- execute highest priorities first, until all are executed
|
||||
local hp = get_highest_priority(actions_now)
|
||||
mesecon.queue:execute(actions_now[hp])
|
||||
table.remove(actions_now, hp)
|
||||
-- stable-sort the executed actions after their priority
|
||||
-- some constructions might depend on the execution order, hence we first
|
||||
-- execute the actions that had a lower index in actions_now
|
||||
local old_action_order = {}
|
||||
for i, ac in ipairs(actions_now) do
|
||||
old_action_order[ac] = i
|
||||
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,
|
||||
-- (e.g. in case the action queue savegame was written by an old mesecons version)
|
||||
if mesecon.queue.funcs[action.func] then
|
||||
mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
|
||||
if queue.funcs[action.func] then
|
||||
queue.funcs[action.func](action.pos, unpack(action.params))
|
||||
end
|
||||
end
|
||||
|
||||
@ -98,8 +142,8 @@ end
|
||||
-- Store and read the ActionQueue to / from a file
|
||||
-- so that upcoming actions are remembered when the game
|
||||
-- is restarted
|
||||
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||
queue.actions = mesecon.file2table("mesecon_actionqueue")
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
|
||||
mesecon.table2file("mesecon_actionqueue", queue.actions)
|
||||
end)
|
||||
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 191 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 844 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 838 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 1.2 KiB 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 |
@ -186,19 +186,11 @@ function mesecon.invertRule(r)
|
||||
return vector.multiply(r, -1)
|
||||
end
|
||||
|
||||
function mesecon.tablecopy(table) -- deep table copy
|
||||
if type(table) ~= "table" then return table end -- no need to copy
|
||||
local newtable = {}
|
||||
|
||||
for idx, item in pairs(table) do
|
||||
if type(item) == "table" then
|
||||
newtable[idx] = mesecon.tablecopy(item)
|
||||
else
|
||||
newtable[idx] = item
|
||||
function mesecon.tablecopy(obj) -- deep copy
|
||||
if type(obj) == "table" then
|
||||
return table.copy(obj)
|
||||
end
|
||||
end
|
||||
|
||||
return newtable
|
||||
return obj
|
||||
end
|
||||
|
||||
function mesecon.cmpAny(t1, t2)
|
||||
|
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 |
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 |
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 |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 183 B |
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,19 +33,9 @@ end
|
||||
|
||||
-- Register the 2 (states) x 4 (delay times) delayers
|
||||
|
||||
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 = { 0.1, 0.3, 0.5, 1.0 }
|
||||
|
||||
local delaytime
|
||||
if i == 1 then delaytime = 0.1
|
||||
elseif i == 2 then delaytime = 0.3
|
||||
elseif i == 3 then delaytime = 0.5
|
||||
elseif i == 4 then delaytime = 1.0 end
|
||||
for i = 1, 4 do
|
||||
|
||||
local boxes = {
|
||||
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
|
||||
@ -61,9 +51,36 @@ local boxes = {
|
||||
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
|
||||
}
|
||||
|
||||
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
description = "Delayer",
|
||||
-- Delayer definition defaults
|
||||
local def = {
|
||||
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 = {
|
||||
"mesecons_delayer_off_"..tostring(i)..".png",
|
||||
"mesecons_delayer_bottom.png",
|
||||
@ -74,35 +91,18 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
},
|
||||
inventory_image = "mesecons_delayer_off_1.png",
|
||||
wield_image = "mesecons_delayer_off_1.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 = groups,
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
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})
|
||||
groups = off_groups,
|
||||
on_punch = function(pos, node, puncher)
|
||||
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.swap_node(pos, {
|
||||
name = "mesecons_delayer:delayer_off_"..tostring(i % 4 + 1),
|
||||
param2 = node.param2
|
||||
})
|
||||
end,
|
||||
delayer_time = delaytime,
|
||||
delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i),
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
receptor =
|
||||
{
|
||||
@ -115,13 +115,15 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
|
||||
action_on = delayer_activate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
}
|
||||
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)
|
||||
|
||||
|
||||
minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
-- Activated delayer definition defaults
|
||||
local on_state = {
|
||||
description = "You hacker you",
|
||||
drawtype = "nodebox",
|
||||
tiles = {
|
||||
"mesecons_delayer_on_"..tostring(i)..".png",
|
||||
"mesecons_delayer_bottom.png",
|
||||
@ -130,35 +132,18 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
"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},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
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})
|
||||
on_punch = function(pos, node, puncher)
|
||||
if minetest.is_protected(pos, puncher and puncher:get_player_name()) then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.swap_node(pos, {
|
||||
name = "mesecons_delayer:delayer_on_"..tostring(i % 4 + 1),
|
||||
param2 = node.param2
|
||||
})
|
||||
end,
|
||||
delayer_time = delaytime,
|
||||
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
mesecons = {
|
||||
receptor =
|
||||
{
|
||||
@ -171,8 +156,12 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
|
||||
action_off = delayer_deactivate
|
||||
}
|
||||
},
|
||||
on_blast = mesecon.on_blastnode,
|
||||
})
|
||||
}
|
||||
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
|
||||
|
||||
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,8 +1,11 @@
|
||||
The node detector is a receptor. It changes its state when either any node
|
||||
or a specific node is detected. Right-click it to set a nodename to scan for.
|
||||
It can also receive digiline signals. You can either send "GET" and it will
|
||||
respond with the detected nodename or you can send any other string and it will
|
||||
set this string as the node to scan for.
|
||||
It can also receive digiline signals. For example, you can send
|
||||
<code>{distance=4, scanname="default:dirt"}</code>
|
||||
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.
|
||||
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 |
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 |
@ -189,29 +189,50 @@ local function node_detector_scan(pos)
|
||||
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
|
||||
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
|
||||
local node_detector_digiline = {
|
||||
effector = {
|
||||
action = function(pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local distance = meta:get_int("distance")
|
||||
local distance_max = mesecon.setting("node_detector_distance_max", 10)
|
||||
if distance < 0 then distance = 0 end
|
||||
if distance > distance_max then distance = distance_max end
|
||||
|
||||
if channel ~= meta:get_string("digiline_channel") then return end
|
||||
|
||||
if 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
|
||||
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)
|
||||
node_detector_send_node_name(pos, node, channel, meta)
|
||||
else
|
||||
meta:set_string("scanname", msg)
|
||||
node_detector_make_formspec(pos)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
receptor = {}
|
||||
|
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 |
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 |
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 |
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 |
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 |
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 |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 519 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
@ -1,10 +1,11 @@
|
||||
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
|
||||
@ -93,16 +94,20 @@ plg.register_nodes({
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
meta:set_int("valid", 0)
|
||||
meta:set_string("formspec", plg.to_formspec_string(is))
|
||||
meta:set_string("infotext", "FPGA")
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, sender)
|
||||
if fields.program == nil then return end -- we only care when the user clicks "Program"
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
if not minetest.is_player(clicker) then
|
||||
return
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local is = plg.from_formspec_fields(fields)
|
||||
local name = clicker:get_player_name()
|
||||
-- Erase formspecs of old FPGAs
|
||||
meta:set_string("formspec", "")
|
||||
|
||||
meta:set_string("instr", lcore.serialize(is))
|
||||
plg.update_formspec(pos, is)
|
||||
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 = {
|
||||
@ -116,6 +121,12 @@ plg.register_nodes({
|
||||
},
|
||||
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)
|
||||
@ -153,13 +164,12 @@ plg.register_nodes({
|
||||
end
|
||||
|
||||
meta:set_string("instr", lcore.serialize(instr))
|
||||
plg.update_formspec(pos, instr)
|
||||
plg.update_meta(pos, instr)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
plg.to_formspec_string = function(is)
|
||||
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?
|
||||
@ -180,26 +190,20 @@ plg.to_formspec_string = function(is)
|
||||
return s .. "]"
|
||||
end
|
||||
local function dropdown_action(x, y, name, val)
|
||||
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
|
||||
.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored?
|
||||
s = s .. " , AND, OR, NOT, XOR,NAND, =,XNOR;"
|
||||
if val == nil then
|
||||
return s .. "0]" -- actually selects no field at all
|
||||
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
|
||||
local mapping = {
|
||||
["and"] = 1,
|
||||
["or"] = 2,
|
||||
["not"] = 3,
|
||||
["xor"] = 4,
|
||||
["nand"] = 5,
|
||||
["buf"] = 6,
|
||||
["xnor"] = 7,
|
||||
}
|
||||
return s .. tostring(1 + mapping[val]) .. "]"
|
||||
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_exit[7,7.5;2,2.5;program;Program]"..
|
||||
"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]"..
|
||||
@ -225,6 +229,12 @@ plg.to_formspec_string = function(is)
|
||||
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
|
||||
|
||||
@ -239,20 +249,11 @@ plg.from_formspec_fields = function(fields)
|
||||
end
|
||||
end
|
||||
local function read_action(s)
|
||||
if s == nil or s == " " then
|
||||
return nil
|
||||
for i, data in ipairs(lcore.get_operations()) do
|
||||
if data.fs_name == s then
|
||||
return data.gate
|
||||
end
|
||||
end
|
||||
local mapping = {
|
||||
["AND"] = "and",
|
||||
["OR"] = "or",
|
||||
["NOT"] = "not",
|
||||
["XOR"] = "xor",
|
||||
["NAND"] = "nand",
|
||||
["="] = "buf",
|
||||
["XNOR"] = "xnor",
|
||||
}
|
||||
s = s:gsub("^%s*", "") -- remove leading spaces
|
||||
return mapping[s]
|
||||
end
|
||||
local is = {}
|
||||
for i = 1, 14 do
|
||||
@ -266,12 +267,11 @@ plg.from_formspec_fields = function(fields)
|
||||
return is
|
||||
end
|
||||
|
||||
plg.update_formspec = function(pos, is)
|
||||
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 form = plg.to_formspec_string(is)
|
||||
|
||||
local err = lcore.validate(is)
|
||||
if err == nil then
|
||||
@ -280,17 +280,20 @@ plg.update_formspec = function(pos, is)
|
||||
else
|
||||
meta:set_int("valid", 0)
|
||||
meta:set_string("infotext", "FPGA")
|
||||
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
|
||||
form = form .. plg.red_box_around(err.i) ..
|
||||
"label[0.25,8.25;The gate configuration is erroneous in the marked area:]"..
|
||||
"label[0.25,8.5;" .. fmsg .. "]"
|
||||
end
|
||||
|
||||
meta:set_string("formspec", form)
|
||||
|
||||
-- reset ports and run programmed logic
|
||||
plg.setports(pos, false, false, false, false)
|
||||
plg.update(pos)
|
||||
|
||||
-- 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)
|
||||
@ -409,6 +412,38 @@ plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
|
||||
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",
|
||||
|
@ -1,5 +1,27 @@
|
||||
|
||||
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)
|
||||
@ -11,20 +33,14 @@ lg.serialize = function(t)
|
||||
return tostring(t.n)
|
||||
end
|
||||
end
|
||||
local function _action(s)
|
||||
if s == nil then
|
||||
return " "
|
||||
-- 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
|
||||
local mapping = {
|
||||
["and"] = "&",
|
||||
["or"] = "|",
|
||||
["not"] = "~",
|
||||
["xor"] = "^",
|
||||
["nand"] = "?", --dunno
|
||||
["buf"] = "_",
|
||||
["xnor"] = "=",
|
||||
}
|
||||
return mapping[s]
|
||||
end
|
||||
return " "
|
||||
end
|
||||
|
||||
local s = ""
|
||||
@ -48,18 +64,14 @@ lg.deserialize = function(s)
|
||||
return {type = "reg", n = tonumber(c)}
|
||||
end
|
||||
end
|
||||
local function _action(c)
|
||||
local mapping = {
|
||||
["&"] = "and",
|
||||
["|"] = "or",
|
||||
["~"] = "not",
|
||||
["^"] = "xor",
|
||||
["?"] = "nand",
|
||||
["_"] = "buf",
|
||||
["="] = "xnor",
|
||||
[" "] = nil,
|
||||
}
|
||||
return mapping[c]
|
||||
-- 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 = {}
|
||||
@ -109,16 +121,25 @@ lg.validate_single = function(t, i)
|
||||
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 elem.action == nil then
|
||||
return {i = i, msg = "Gate type required"}
|
||||
elseif elem.action == "not" or elem.action == "buf" then
|
||||
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 required"}
|
||||
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 required"}
|
||||
return {i = i, msg = "Operands and destination are required"}
|
||||
end
|
||||
end
|
||||
-- check whether operands/destination are identical
|
||||
@ -159,22 +180,13 @@ end
|
||||
-- interpreter
|
||||
lg.interpret = function(t, a, b, c, d)
|
||||
local function _action(s, v1, v2)
|
||||
if s == "and" then
|
||||
return v1 and v2
|
||||
elseif s == "or" then
|
||||
return v1 or v2
|
||||
elseif s == "not" then
|
||||
return not v2
|
||||
elseif s == "xor" then
|
||||
return v1 ~= v2
|
||||
elseif s == "nand" then
|
||||
return not (v1 and v2)
|
||||
elseif s == "buf" then
|
||||
return v2
|
||||
else -- s == "xnor"
|
||||
return v1 == v2
|
||||
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]
|
||||
|
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 536 B After Width: | Height: | Size: 480 B |
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 760 B |
@ -34,17 +34,22 @@ minetest.register_tool("mesecons_fpga:programmer", {
|
||||
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
|
||||
return itemstack
|
||||
end
|
||||
local player_name = user:get_player_name()
|
||||
if minetest.is_protected(pos, player_name) then
|
||||
minetest.record_protection_violation(pos, player_name)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local imeta = itemstack:get_metadata()
|
||||
if imeta == "" then
|
||||
minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.")
|
||||
minetest.chat_send_player(player_name, "Use shift+right-click to copy a gate configuration first.")
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("instr", imeta)
|
||||
plg.update_formspec(pos, imeta)
|
||||
minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!")
|
||||
plg.update_meta(pos, imeta)
|
||||
minetest.chat_send_player(player_name, "Gate configuration was successfully written to FPGA!")
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -1,6 +1,14 @@
|
||||
local selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }
|
||||
}
|
||||
|
||||
local nodebox = {
|
||||
type = "fixed",
|
||||
fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }},
|
||||
fixed = {
|
||||
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
|
||||
{ -6/16, -7/16, -6/16, 6/16, -6/16, 6/16 }
|
||||
},
|
||||
}
|
||||
|
||||
local function gate_rotate_rules(node, rules)
|
||||
@ -68,7 +76,7 @@ local function register_gate(name, inputnumber, assess, recipe, description)
|
||||
is_ground_content = false,
|
||||
drawtype = "nodebox",
|
||||
drop = basename.."_off",
|
||||
selection_box = nodebox,
|
||||
selection_box = selection_box,
|
||||
node_box = nodebox,
|
||||
walkable = true,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
@ -78,8 +86,16 @@ local function register_gate(name, inputnumber, assess, recipe, description)
|
||||
inputnumber = inputnumber,
|
||||
after_dig_node = mesecon.do_cooldown,
|
||||
},{
|
||||
tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
|
||||
"jeija_gate_"..name..".png"},
|
||||
tiles = {
|
||||
"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
|
||||
"jeija_gate_output_off.png^".."jeija_gate_"..name..".png",
|
||||
"jeija_microcontroller_bottom.png^".."jeija_gate_output_off.png^"..
|
||||
"[transformFY",
|
||||
"jeija_gate_side.png^".."jeija_gate_side_output_off.png",
|
||||
"jeija_gate_side.png",
|
||||
"jeija_gate_side.png",
|
||||
"jeija_gate_side.png"
|
||||
},
|
||||
groups = {dig_immediate = 2, overheat = 1},
|
||||
mesecons = { receptor = {
|
||||
state = "off",
|
||||
@ -89,8 +105,16 @@ local function register_gate(name, inputnumber, assess, recipe, description)
|
||||
action_change = update_gate
|
||||
}}
|
||||
},{
|
||||
tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^"..
|
||||
"jeija_gate_"..name..".png"},
|
||||
tiles = {
|
||||
"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^"..
|
||||
"jeija_gate_output_on.png^".."jeija_gate_"..name..".png",
|
||||
"jeija_microcontroller_bottom.png^".."jeija_gate_output_on.png^"..
|
||||
"[transformFY",
|
||||
"jeija_gate_side.png^".."jeija_gate_side_output_on.png",
|
||||
"jeija_gate_side.png",
|
||||
"jeija_gate_side.png",
|
||||
"jeija_gate_side.png"
|
||||
},
|
||||
groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1},
|
||||
mesecons = { receptor = {
|
||||
state = "on",
|
||||
|
Before Width: | Height: | Size: 233 B After Width: | Height: | Size: 123 B |
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 241 B After Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 84 B |
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 84 B |
Before Width: | Height: | Size: 243 B After Width: | Height: | Size: 127 B |
BIN
mesecons_gates/textures/jeija_gate_output_off.png
Normal file
After Width: | Height: | Size: 98 B |
BIN
mesecons_gates/textures/jeija_gate_output_on.png
Normal file
After Width: | Height: | Size: 99 B |
BIN
mesecons_gates/textures/jeija_gate_side.png
Normal file
After Width: | Height: | Size: 136 B |
BIN
mesecons_gates/textures/jeija_gate_side_output_off.png
Normal file
After Width: | Height: | Size: 109 B |
BIN
mesecons_gates/textures/jeija_gate_side_output_on.png
Normal file
After Width: | Height: | Size: 110 B |
Before Width: | Height: | Size: 245 B After Width: | Height: | Size: 128 B |