1 Commits

Author SHA1 Message Date
7888566b2f Use table.copy in mesecons.tablecopy
mesecons.tablecopy didn’t support recursive tables, while Minetest table.copy works well for them.
2019-09-21 21:09:46 +00:00
111 changed files with 438 additions and 1014 deletions

2
.gitignore vendored
View File

@ -1,3 +1 @@
*~ *~
*.patch
*.diff

View File

@ -1,140 +1,96 @@
--[[ mesecon.queue.actions={} -- contains all ActionQueue actions
Mesecons uses something it calls an ActionQueue.
The ActionQueue holds functions and actions. function mesecon.queue:add_function(name, func)
Functions are added on load time with a specified name. mesecon.queue.funcs[name] = func
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 queue:add_action(pos, func, params, time, overwritecheck, priority) function mesecon.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 = { local action = { pos=mesecon.tablecopy(pos),
pos = mesecon.tablecopy(pos), func=func,
func = func, params=mesecon.tablecopy(params or {}),
params = mesecon.tablecopy(params or {}), time=time,
time = time, owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil,
owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil, priority=priority}
priority = priority
}
-- check if old action has to be overwritten / removed: local toremove = nil
if overwritecheck then -- Otherwise, add the action to the queue
for i, ac in ipairs(queue.actions) do if overwritecheck then -- check if old action has to be overwritten / removed:
if vector.equals(pos, ac.pos) for i, ac in ipairs(mesecon.queue.actions) do
and mesecon.cmpAny(overwritecheck, ac.owcheck) then if(vector.equals(pos, ac.pos)
-- remove the old action and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
table.remove(queue.actions, i) toremove = i
break break
end end
end end
end end
table.insert(queue.actions, action) if (toremove ~= nil) then
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 (hm, where do we do this?) -- this makes sure that resuming mesecons circuits when restarting minetest works fine
-- However, even that does not work in some cases, that's why we delay the time the globalsteps -- However, even that does not work in some cases, that's why we delay the time the globalsteps
-- start to be execute by 4 seconds -- 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
local function globalstep_func(dtime) return highesti
local actions = queue.actions end
-- split into two categories:
-- actions_now: actions to execute now
-- queue.actions: actions to execute later
local actions_now = {}
queue.actions = {}
for _, ac in ipairs(actions) do local m_time = 0
local resumetime = mesecon.setting("resumetime", 4)
minetest.register_globalstep(function (dtime)
m_time = m_time + dtime
-- don't even try if server has not been running for XY seconds; resumetime = time to wait
-- after starting the server before processing the ActionQueue, don't set this too low
if (m_time < resumetime) then return end
local actions = mesecon.tablecopy(mesecon.queue.actions)
local actions_now={}
mesecon.queue.actions = {}
-- sort actions into two categories:
-- those toexecute now (actions_now) and those to execute later (mesecon.queue.actions)
for i, ac in ipairs(actions) do
if ac.time > 0 then if ac.time > 0 then
-- action ac is to be executed later ac.time = ac.time - dtime -- executed later
-- ~> insert into queue.actions table.insert(mesecon.queue.actions, ac)
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
-- stable-sort the executed actions after their priority while(#actions_now > 0) do -- execute highest priorities first, until all are executed
-- some constructions might depend on the execution order, hence we first local hp = get_highest_priority(actions_now)
-- execute the actions that had a lower index in actions_now mesecon.queue:execute(actions_now[hp])
local old_action_order = {} table.remove(actions_now, hp)
for i, ac in ipairs(actions_now) do
old_action_order[ac] = i
end end
table.sort(actions_now, function(ac1, ac2) end)
if ac1.priority ~= ac2.priority then
return ac1.priority > ac2.priority
else
return old_action_order[ac1] < old_action_order[ac2]
end
end)
-- execute highest priorities first, until all are executed function mesecon.queue:execute(action)
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 queue.funcs[action.func] then if mesecon.queue.funcs[action.func] then
queue.funcs[action.func](action.pos, unpack(action.params)) mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
end end
end end
@ -142,8 +98,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
queue.actions = mesecon.file2table("mesecon_actionqueue") mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
minetest.register_on_shutdown(function() minetest.register_on_shutdown(function()
mesecon.table2file("mesecon_actionqueue", queue.actions) mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
end) end)

1
mesecons/depends.txt Normal file
View File

@ -0,0 +1 @@
default

View File

@ -92,8 +92,8 @@ function mesecon.get_any_inputrules(node)
end end
function mesecon.get_any_rules(node) function mesecon.get_any_rules(node)
return mesecon.merge_rule_sets(mesecon.get_any_inputrules(node), return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
mesecon.get_any_outputrules(node)) mesecon.get_any_outputrules(node) or {})
end end
-- Receptors -- Receptors

View File

@ -1,2 +0,0 @@
name = mesecons
depends = default

View File

@ -16,9 +16,9 @@ mesecon.rules.default = {
{x = 0, y = -1, z = -1}, {x = 0, y = -1, z = -1},
} }
mesecon.rules.floor = mesecon.merge_rule_sets(mesecon.rules.default, {{x = 0, y = -1, z = 0}}) mesecon.rules.floor = mesecon.mergetable(mesecon.rules.default, {{x = 0, y = -1, z = 0}})
mesecon.rules.pplate = mesecon.merge_rule_sets(mesecon.rules.floor, {{x = 0, y = -2, z = 0}}) mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.floor, {{x = 0, y = -2, z = 0}})
mesecon.rules.buttonlike = { mesecon.rules.buttonlike = {
{x = 1, y = 0, z = 0}, {x = 1, y = 0, z = 0},

View File

@ -193,29 +193,19 @@ function mesecon.tablecopy(obj) -- deep copy
return obj return obj
end end
-- Returns whether two values are equal.
-- In tables, keys are compared for identity but values are compared recursively.
-- There is no protection from infinite recursion.
function mesecon.cmpAny(t1, t2) function mesecon.cmpAny(t1, t2)
if type(t1) ~= type(t2) then return false end if type(t1) ~= type(t2) then return false end
if type(t1) ~= "table" then return t1 == t2 end if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end
-- Check that for each key of `t1` both tables have the same value
for i, e in pairs(t1) do for i, e in pairs(t1) do
if not mesecon.cmpAny(e, t2[i]) then return false end if not mesecon.cmpAny(e, t2[i]) then return false end
end end
-- Check that all keys of `t2` are also keys of `t1` so were checked in the previous loop
for i, _ in pairs(t2) do
if t1[i] == nil then return false end
end
return true return true
end end
-- Deprecated. Use `merge_tables` or `merge_rule_sets` as appropriate. -- does not overwrite values; number keys (ipairs) are appended, not overwritten
function mesecon.mergetable(source, dest) function mesecon.mergetable(source, dest)
minetest.log("warning", debug.traceback("Deprecated call to mesecon.mergetable"))
local rval = mesecon.tablecopy(dest) local rval = mesecon.tablecopy(dest)
for k, v in pairs(source) do for k, v in pairs(source) do
@ -228,32 +218,6 @@ function mesecon.mergetable(source, dest)
return rval return rval
end end
-- Merges several rule sets in one. Order may not be preserved. Nil arguments
-- are ignored.
-- The rule sets must be of the same kind (either all single-level or all two-level).
-- The function may be changed to normalize the resulting set in some way.
function mesecon.merge_rule_sets(...)
local rval = {}
for _, t in pairs({...}) do -- ignores nils automatically
table.insert_all(rval, mesecon.tablecopy(t))
end
return rval
end
-- Merges two tables, with entries from `replacements` taking precedence over
-- those from `base`. Returns the new table.
-- Values are deep-copied from either table, keys are referenced.
-- Numerical indices arent handled specially.
function mesecon.merge_tables(base, replacements)
local ret = mesecon.tablecopy(replacements) -- these are never overriden so have to be copied in any case
for k, v in pairs(base) do
if ret[k] == nil then -- it could be `false`
ret[k] = mesecon.tablecopy(v)
end
end
return ret
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.on_blast = spec_common.on_blast or mesecon.on_blastnode
@ -261,8 +225,8 @@ function mesecon.register_node(name, spec_common, spec_off, spec_on)
spec_on.__mesecon_state = "on" spec_on.__mesecon_state = "on"
spec_off.__mesecon_state = "off" spec_off.__mesecon_state = "off"
spec_on = mesecon.merge_tables(spec_common, spec_on); spec_on = mesecon.mergetable(spec_common, spec_on);
spec_off = mesecon.merge_tables(spec_common, spec_off); spec_off = mesecon.mergetable(spec_common, spec_off);
minetest.register_node(name .. "_on", spec_on) minetest.register_node(name .. "_on", spec_on)
minetest.register_node(name .. "_off", spec_off) minetest.register_node(name .. "_off", spec_off)

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_alias
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -32,13 +32,7 @@ mesecon.register_node("mesecons_blinkyplant:blinky_plant", {
fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3},
}, },
on_timer = on_timer, on_timer = on_timer,
on_rightclick = function(pos, node, clicker) on_rightclick = toggle_timer,
if minetest.is_protected(pos, clicker and clicker:get_player_name() or "") then
return
end
toggle_timer(pos)
end,
on_construct = toggle_timer on_construct = toggle_timer
},{ },{
tiles = {"jeija_blinky_plant_off.png"}, tiles = {"jeija_blinky_plant_off.png"},

View File

@ -1,2 +0,0 @@
name = mesecons_blinkyplant
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
mesecons_receiver

View File

@ -8,7 +8,7 @@ mesecon.button_turnoff = function (pos)
return return
end end
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2}) minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2})
minetest.sound_play("mesecons_button_pop", { pos = pos }, true) 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
@ -46,7 +46,7 @@ minetest.register_node("mesecons_button:button_off", {
on_rightclick = function (pos, node) on_rightclick = function (pos, node)
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 }, true) minetest.sound_play("mesecons_button_push", {pos=pos})
minetest.get_node_timer(pos):start(1) minetest.get_node_timer(pos):start(1)
end, end,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),

View File

@ -1,2 +0,0 @@
name = mesecons_button
depends = mesecons, mesecons_receiver

View File

@ -0,0 +1 @@
mesecons

View File

@ -110,7 +110,7 @@ local function resolve_commands(commands, pos)
local nearest, farthest = nil, nil local nearest, farthest = nil, nil
local min_distance, max_distance = math.huge, -1 local min_distance, max_distance = math.huge, -1
for index, player in pairs(players) do for index, player in pairs(players) do
local distance = vector.distance(pos, player:get_pos()) local distance = vector.distance(pos, player:getpos())
if distance < min_distance then if distance < min_distance then
min_distance = distance min_distance = distance
nearest = player:get_player_name() nearest = player:get_player_name()
@ -174,8 +174,7 @@ end
local function can_dig(pos, player) local function can_dig(pos, player)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner") local owner = meta:get_string("owner")
return owner == "" or owner == player:get_player_name() or return owner == "" or owner == player:get_player_name()
minetest.check_player_privs(player, "protection_bypass")
end end
minetest.register_node("mesecons_commandblock:commandblock_off", { minetest.register_node("mesecons_commandblock:commandblock_off", {

View File

@ -1,2 +0,0 @@
name = mesecons_commandblock
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -33,9 +33,19 @@ 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
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
local boxes = { local boxes = {
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab { -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
@ -51,9 +61,19 @@ local boxes = {
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 } { 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
} }
-- Delayer definition defaults minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
local def = { description = "Delayer",
drawtype = "nodebox", drawtype = "nodebox",
tiles = {
"mesecons_delayer_off_"..tostring(i)..".png",
"mesecons_delayer_bottom.png",
"mesecons_delayer_ends_off.png",
"mesecons_delayer_ends_off.png",
"mesecons_delayer_sides_off.png",
"mesecons_delayer_sides_off.png"
},
inventory_image = "mesecons_delayer_off_1.png",
wield_image = "mesecons_delayer_off_1.png",
walkable = true, walkable = true,
selection_box = { selection_box = {
type = "fixed", type = "fixed",
@ -63,46 +83,26 @@ local def = {
type = "fixed", type = "fixed",
fixed = boxes fixed = boxes
}, },
groups = groups,
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true, sunlight_propagates = true,
is_ground_content = false, is_ground_content = false,
delayer_time = delaytime[i], drop = 'mesecons_delayer:delayer_off_1',
sounds = default.node_sound_stone_defaults(), on_punch = function (pos, node)
on_blast = mesecon.on_blastnode, if node.name=="mesecons_delayer:delayer_off_1" then
drop = "mesecons_delayer:delayer_off_1", 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})
-- Deactivated delayer definition defaults elseif node.name=="mesecons_delayer:delayer_off_3" then
local off_groups = {bendy=2,snappy=1,dig_immediate=2} minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_4", param2=node.param2})
if i > 1 then elseif node.name=="mesecons_delayer:delayer_off_4" then
off_groups.not_in_creative_inventory = 1 minetest.swap_node(pos, {name = "mesecons_delayer:delayer_off_1", param2=node.param2})
end
local off_state = {
description = "Delayer",
tiles = {
"mesecons_delayer_off_"..tostring(i)..".png",
"mesecons_delayer_bottom.png",
"mesecons_delayer_ends_off.png",
"mesecons_delayer_ends_off.png",
"mesecons_delayer_sides_off.png",
"mesecons_delayer_sides_off.png"
},
inventory_image = "mesecons_delayer_off_1.png",
wield_image = "mesecons_delayer_off_1.png",
groups = off_groups,
on_punch = function(pos, node, puncher)
if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then
return
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 =
{ {
@ -115,15 +115,13 @@ local off_state = {
action_on = delayer_activate 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)
-- Activated delayer definition defaults
local on_state = { minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
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",
@ -131,19 +129,36 @@ local on_state = {
"mesecons_delayer_ends_on.png", "mesecons_delayer_ends_on.png",
"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},
on_punch = function(pos, node, puncher) paramtype = "light",
if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then paramtype2 = "facedir",
return 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})
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),
sounds = default.node_sound_stone_defaults(),
mesecons = { mesecons = {
receptor = receptor =
{ {
@ -156,12 +171,8 @@ local on_state = {
action_off = delayer_deactivate 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 end
minetest.register_craft({ minetest.register_craft({

View File

@ -1,2 +0,0 @@
name = mesecons_delayer
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
mesecons_materials

View File

@ -239,7 +239,7 @@ local node_detector_digiline = {
} }
local function after_place_node_detector(pos, placer) local function after_place_node_detector(pos, placer)
local placer_pos = placer:get_pos() local placer_pos = placer:getpos()
if not placer_pos then if not placer_pos then
return return
end end

View File

@ -1,2 +0,0 @@
name = mesecons_detector
depends = mesecons, mesecons_materials

View File

@ -0,0 +1,2 @@
mesecons
doors

View File

@ -13,9 +13,9 @@ local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
minetest.swap_node(pos, {name = replace, param2 = p2}) minetest.swap_node(pos, {name = replace, param2 = p2})
if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then
minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
else else
minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
end end
end end
@ -73,17 +73,16 @@ meseconify_door("doors:door_wood")
meseconify_door("doors:door_steel") meseconify_door("doors:door_steel")
meseconify_door("doors:door_glass") meseconify_door("doors:door_glass")
meseconify_door("doors:door_obsidian_glass") meseconify_door("doors:door_obsidian_glass")
meseconify_door("xpanes:door_steel_bar")
-- Trapdoor -- Trapdoor
local function trapdoor_switch(pos, node) local function trapdoor_switch(pos, node)
local state = minetest.get_meta(pos):get_int("state") local state = minetest.get_meta(pos):get_int("state")
if state == 1 then if state == 1 then
minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.set_node(pos, {name="doors:trapdoor", param2 = node.param2}) minetest.set_node(pos, {name="doors:trapdoor", param2 = node.param2})
else else
minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.set_node(pos, {name="doors:trapdoor_open", param2 = node.param2}) minetest.set_node(pos, {name="doors:trapdoor_open", param2 = node.param2})
end end
@ -111,12 +110,6 @@ if doors and doors.get then
minetest.override_item("doors:trapdoor_open", override) minetest.override_item("doors:trapdoor_open", override)
minetest.override_item("doors:trapdoor_steel", override) minetest.override_item("doors:trapdoor_steel", override)
minetest.override_item("doors:trapdoor_steel_open", override) minetest.override_item("doors:trapdoor_steel_open", override)
if minetest.registered_items["xpanes:trapdoor_steel_bar"] then
minetest.override_item("xpanes:trapdoor_steel_bar", override)
minetest.override_item("xpanes:trapdoor_steel_bar_open", override)
end
else else
if minetest.registered_nodes["doors:trapdoor"] then if minetest.registered_nodes["doors:trapdoor"] then
minetest.override_item("doors:trapdoor", { minetest.override_item("doors:trapdoor", {

View File

@ -1,3 +0,0 @@
name = mesecons_doors
depends = mesecons, doors
optional_depends = xpanes

View File

@ -1,5 +1,12 @@
local screwdriver_exists = minetest.global_exists("screwdriver") local screwdriver_exists = minetest.global_exists("screwdriver")
local corner_nodebox = {
type = "fixed",
-- ±0.001 is to prevent z-fighting
fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 },
{ -3/32, -17/32, -16/32+0.001, 3/32, -13/32, 3/32}}
}
local corner_selectionbox = { local corner_selectionbox = {
type = "fixed", type = "fixed",
fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 }, fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 },
@ -18,11 +25,14 @@ local corner_get_rules = function (node)
end end
minetest.register_node("mesecons_extrawires:corner_on", { minetest.register_node("mesecons_extrawires:corner_on", {
drawtype = "mesh", drawtype = "nodebox",
mesh = "mesecons_extrawires_corner.obj",
tiles = { tiles = {
{ name = "jeija_insulated_wire_sides_on.png", backface_culling = true }, "jeija_insulated_wire_curved_tb_on.png",
{ name = "jeija_insulated_wire_ends_on.png", backface_culling = true }, "jeija_insulated_wire_curved_tb_on.png^[transformR270",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_on.png"
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
@ -45,12 +55,15 @@ minetest.register_node("mesecons_extrawires:corner_on", {
}) })
minetest.register_node("mesecons_extrawires:corner_off", { minetest.register_node("mesecons_extrawires:corner_off", {
drawtype = "mesh", drawtype = "nodebox",
description = "Insulated Mesecon Corner", description = "Insulated Mesecon Corner",
mesh = "mesecons_extrawires_corner.obj",
tiles = { tiles = {
{ name = "jeija_insulated_wire_sides_off.png", backface_culling = true }, "jeija_insulated_wire_curved_tb_off.png",
{ name = "jeija_insulated_wire_ends_off.png", backface_culling = true }, "jeija_insulated_wire_curved_tb_off.png^[transformR270",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_off.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_off.png"
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
@ -74,7 +87,8 @@ minetest.register_node("mesecons_extrawires:corner_off", {
minetest.register_craft({ minetest.register_craft({
output = "mesecons_extrawires:corner_off 3", output = "mesecons_extrawires:corner_off 3",
recipe = { recipe = {
{"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"}, {"", "", ""},
{"", "mesecons_insulated:insulated_off"}, {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", ""},
{"", "mesecons_insulated:insulated_off", ""},
} }
}) })

View File

@ -0,0 +1,3 @@
default
mesecons
screwdriver?

View File

@ -1,91 +0,0 @@
local rotate
if minetest.global_exists("screwdriver") then rotate = screwdriver.rotate_simple end
local doublecorner_selectionbox = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
}
local rules = {
{
{ x = 1, y = 0, z = 0 },
{ x = 0, y = 0, z = 1 },
},
{
{ x = -1, y = 0, z = 0 },
{ x = 0, y = 0, z = -1 },
},
}
local doublecorner_rules = {}
for k = 1, 4 do
doublecorner_rules[k] = table.copy(rules)
for i, r in ipairs(rules) do
rules[i] = mesecon.rotate_rules_left(r)
end
end
local function doublecorner_get_rules(node)
return doublecorner_rules[node.param2 % 4 + 1]
end
local doublecorner_states = {
"mesecons_extrawires:doublecorner_00",
"mesecons_extrawires:doublecorner_01",
"mesecons_extrawires:doublecorner_10",
"mesecons_extrawires:doublecorner_11",
}
local wire1_states = { "off", "off", "on", "on" }
local wire2_states = { "off", "on", "off", "on" }
for k, state in ipairs(doublecorner_states) do
local w1 = wire1_states[k]
local w2 = wire2_states[k]
local groups = { dig_immediate = 3 }
if k ~= 1 then groups.not_in_creative_inventory = 1 end
minetest.register_node(state, {
drawtype = "mesh",
mesh = "mesecons_extrawires_doublecorner.obj",
description = "Insulated Mesecon Double Corner",
tiles = {
{ name = "jeija_insulated_wire_sides_" .. w1 .. ".png", backface_culling = true },
{ name = "jeija_insulated_wire_ends_" .. w1 .. ".png", backface_culling = true },
{ name = "jeija_insulated_wire_sides_" .. w2 .. ".png", backface_culling = true },
{ name = "jeija_insulated_wire_ends_" .. w2 .. ".png", backface_culling = true },
},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
walkable = false,
sunlight_propagates = true,
selection_box = doublecorner_selectionbox,
groups = groups,
drop = doublecorner_states[1],
sounds = default.node_sound_defaults(),
mesecons = {
conductor = {
states = doublecorner_states,
rules = doublecorner_get_rules,
},
},
on_blast = mesecon.on_blastnode,
on_rotate = rotate,
})
end
minetest.register_craft({
type = "shapeless",
output = "mesecons_extrawires:doublecorner_00",
recipe = {
"mesecons_extrawires:corner_off",
"mesecons_extrawires:corner_off",
},
})
minetest.register_craft({
type = "shapeless",
output = "mesecons_extrawires:corner_off 2",
recipe = {
"mesecons_extrawires:doublecorner_00",
},
})

View File

@ -1,6 +1,5 @@
dofile(minetest.get_modpath("mesecons_extrawires").."/crossover.lua"); dofile(minetest.get_modpath("mesecons_extrawires").."/crossover.lua");
dofile(minetest.get_modpath("mesecons_extrawires").."/tjunction.lua"); dofile(minetest.get_modpath("mesecons_extrawires").."/tjunction.lua");
dofile(minetest.get_modpath("mesecons_extrawires").."/corner.lua"); dofile(minetest.get_modpath("mesecons_extrawires").."/corner.lua");
dofile(minetest.get_modpath("mesecons_extrawires").."/doublecorner.lua");
dofile(minetest.get_modpath("mesecons_extrawires").."/vertical.lua"); dofile(minetest.get_modpath("mesecons_extrawires").."/vertical.lua");
dofile(minetest.get_modpath("mesecons_extrawires").."/mesewire.lua"); dofile(minetest.get_modpath("mesecons_extrawires").."/mesewire.lua");

View File

@ -18,7 +18,7 @@ minetest.override_item("default:mese", {
-- Copy node definition of powered mese from normal mese -- Copy node definition of powered mese from normal mese
-- and brighten texture tiles to indicate mese is powered -- and brighten texture tiles to indicate mese is powered
local powered_def = mesecon.merge_tables(minetest.registered_nodes["default:mese"], { local powered_def = mesecon.mergetable(minetest.registered_nodes["default:mese"], {
drop = "default:mese", drop = "default:mese",
light_source = 5, light_source = 5,
mesecons = {conductor = { mesecons = {conductor = {

View File

@ -1,3 +0,0 @@
name = mesecons_extrawires
depends = default, mesecons
optional_depends = screwdriver

View File

@ -1,125 +0,0 @@
# Вершины
# Провод 1
# 1 (ниж. внутр.)
v 0.093750 -0.531250 -0.501000
v 0.093750 -0.531250 -0.331726
v 0.331726 -0.531250 -0.093750
v 0.501000 -0.531250 -0.093750
# 5 (ниж. наруж.)
v -0.093750 -0.531250 -0.501000
v -0.093750 -0.531250 -0.254061
v 0.254061 -0.531250 0.093750
v 0.501000 -0.531250 0.093750
# 9 (верх. внутр.)
v 0.093750 -0.406250 -0.501000
v 0.093750 -0.406250 -0.331726
v 0.331726 -0.406250 -0.093750
v 0.501000 -0.406250 -0.093750
# 13 (верх. наруж.)
v -0.093750 -0.406250 -0.501000
v -0.093750 -0.406250 -0.254061
v 0.254061 -0.406250 0.093750
v 0.501000 -0.406250 0.093750
# Текстурные координаты
# 1 (ниж.)
vt 0.000000 0.406250
vt 0.168274 0.406250
vt 0.331726 0.406250
vt 0.668274 0.406250
vt 0.831726 0.406250
vt 1.000000 0.406250
vt 0.000000 0.593750
vt 0.245939 0.593750
vt 0.254061 0.593750
vt 0.745939 0.593750
vt 0.754061 0.593750
vt 1.000000 0.593750
# 13 (верх.)
vt 0.000000 0.406250
vt 0.245939 0.406250
vt 0.254061 0.406250
vt 0.745939 0.406250
vt 0.754061 0.406250
vt 1.000000 0.406250
vt 0.000000 0.593750
vt 0.168274 0.593750
vt 0.331726 0.593750
vt 0.668274 0.593750
vt 0.831726 0.593750
vt 1.000000 0.593750
# 25 (внутр.)
vt 1.000000 0.093750
vt 0.831726 0.093750
vt 0.668274 0.093750
vt 0.331726 0.093750
vt 0.168274 0.093750
vt 0.000000 0.093750
vt 1.000000 -0.031250
vt 0.831726 -0.031250
vt 0.668274 -0.031250
vt 0.331726 -0.031250
vt 0.168274 -0.031250
vt 0.000000 -0.031250
# 37 (внеш.)
vt 0.000000 -0.031250
vt 0.245939 -0.031250
vt 0.254061 -0.031250
vt 0.745939 -0.031250
vt 0.754061 -0.031250
vt 1.000000 -0.031250
vt 0.000000 0.093750
vt 0.245939 0.093750
vt 0.254061 0.093750
vt 0.745939 0.093750
vt 0.754061 0.093750
vt 1.000000 0.093750
# 49 (торец)
vt 0.406250 -0.031250
vt 0.406250 0.093750
vt 0.593750 -0.031250
vt 0.593750 0.093750
# Нормали
# 1
vn 1.000000 0.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.707107 0.000000 0.707107
# 5
vn -1.000000 0.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn -0.707107 0.000000 -0.707107
# Грани
g Sides1
# Часть 1
f 5/37/1 6/38/1 14/44/1
f 5/37/1 14/44/1 13/43/1
f 13/13/2 14/14/2 10/20/2
f 13/13/2 10/20/2 9/19/2
f 9/25/5 10/26/5 2/32/5
f 9/25/5 2/32/5 1/31/5
f 1/1/6 2/2/6 6/8/6
f 1/1/6 6/8/6 5/7/6
# Часть 2
f 6/39/4 7/40/4 15/46/4
f 6/39/4 15/46/4 14/45/4
f 14/15/2 15/16/2 11/22/2
f 14/15/2 11/22/2 10/21/2
f 10/27/8 11/28/8 3/34/8
f 10/27/8 3/34/8 2/33/8
f 2/3/6 3/4/6 7/10/6
f 2/3/6 7/10/6 6/9/6
# Часть 3
f 7/41/3 8/42/3 16/48/3
f 7/41/3 16/48/3 15/47/3
f 15/17/2 16/18/2 12/24/2
f 15/17/2 12/24/2 11/23/2
f 11/29/7 12/30/7 4/36/7
f 11/29/7 4/36/7 3/35/7
f 3/5/6 4/6/6 8/12/6
f 3/5/6 8/12/6 7/11/6
g Ends1
f 1/49/3 5/51/3 13/52/3
f 1/49/3 13/52/3 9/50/3
f 4/49/1 12/50/1 16/52/1
f 4/49/1 16/52/1 8/51/1

View File

@ -1,180 +0,0 @@
# Вершины
# Провод 1
# 1 (ниж. внутр.)
v 0.093750 -0.531250 -0.501000
v 0.093750 -0.531250 -0.331726
v 0.331726 -0.531250 -0.093750
v 0.501000 -0.531250 -0.093750
# 5 (ниж. наруж.)
v -0.093750 -0.531250 -0.501000
v -0.093750 -0.531250 -0.254061
v 0.254061 -0.531250 0.093750
v 0.501000 -0.531250 0.093750
# 9 (верх. внутр.)
v 0.093750 -0.406250 -0.501000
v 0.093750 -0.406250 -0.331726
v 0.331726 -0.406250 -0.093750
v 0.501000 -0.406250 -0.093750
# 13 (верх. наруж.)
v -0.093750 -0.406250 -0.501000
v -0.093750 -0.406250 -0.254061
v 0.254061 -0.406250 0.093750
v 0.501000 -0.406250 0.093750
# Провод 2
# 17 (ниж. внутр.)
v -0.093750 -0.531250 0.501000
v -0.093750 -0.531250 0.331726
v -0.331726 -0.531250 0.093750
v -0.501000 -0.531250 0.093750
# 21 (ниж. наруж.)
v 0.093750 -0.531250 0.501000
v 0.093750 -0.531250 0.254061
v -0.254061 -0.531250 -0.093750
v -0.501000 -0.531250 -0.093750
# 25 (верх. внутр.)
v -0.093750 -0.406250 0.501000
v -0.093750 -0.406250 0.331726
v -0.331726 -0.406250 0.093750
v -0.501000 -0.406250 0.093750
# 29 (верх. наруж.)
v 0.093750 -0.406250 0.501000
v 0.093750 -0.406250 0.254061
v -0.254061 -0.406250 -0.093750
v -0.501000 -0.406250 -0.093750
# Текстурные координаты
# 1 (ниж.)
vt 0.000000 0.406250
vt 0.168274 0.406250
vt 0.331726 0.406250
vt 0.668274 0.406250
vt 0.831726 0.406250
vt 1.000000 0.406250
vt 0.000000 0.593750
vt 0.245939 0.593750
vt 0.254061 0.593750
vt 0.745939 0.593750
vt 0.754061 0.593750
vt 1.000000 0.593750
# 13 (верх.)
vt 0.000000 0.406250
vt 0.245939 0.406250
vt 0.254061 0.406250
vt 0.745939 0.406250
vt 0.754061 0.406250
vt 1.000000 0.406250
vt 0.000000 0.593750
vt 0.168274 0.593750
vt 0.331726 0.593750
vt 0.668274 0.593750
vt 0.831726 0.593750
vt 1.000000 0.593750
# 25 (внутр.)
vt 1.000000 0.093750
vt 0.831726 0.093750
vt 0.668274 0.093750
vt 0.331726 0.093750
vt 0.168274 0.093750
vt 0.000000 0.093750
vt 1.000000 -0.031250
vt 0.831726 -0.031250
vt 0.668274 -0.031250
vt 0.331726 -0.031250
vt 0.168274 -0.031250
vt 0.000000 -0.031250
# 37 (внеш.)
vt 0.000000 -0.031250
vt 0.245939 -0.031250
vt 0.254061 -0.031250
vt 0.745939 -0.031250
vt 0.754061 -0.031250
vt 1.000000 -0.031250
vt 0.000000 0.093750
vt 0.245939 0.093750
vt 0.254061 0.093750
vt 0.745939 0.093750
vt 0.754061 0.093750
vt 1.000000 0.093750
# 49 (торец)
vt 0.406250 -0.031250
vt 0.406250 0.093750
vt 0.593750 -0.031250
vt 0.593750 0.093750
# Нормали
# 1
vn 1.000000 0.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.707107 0.000000 0.707107
# 5
vn -1.000000 0.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn -0.707107 0.000000 -0.707107
# Грани
# Грани
g Sides1
# Часть 1
f 5/37/1 6/38/1 14/44/1
f 5/37/1 14/44/1 13/43/1
f 13/13/2 14/14/2 10/20/2
f 13/13/2 10/20/2 9/19/2
f 9/25/5 10/26/5 2/32/5
f 9/25/5 2/32/5 1/31/5
f 1/1/6 2/2/6 6/8/6
f 1/1/6 6/8/6 5/7/6
# Часть 2
f 6/39/4 7/40/4 15/46/4
f 6/39/4 15/46/4 14/45/4
f 14/15/2 15/16/2 11/22/2
f 14/15/2 11/22/2 10/21/2
f 10/27/8 11/28/8 3/34/8
f 10/27/8 3/34/8 2/33/8
f 2/3/6 3/4/6 7/10/6
f 2/3/6 7/10/6 6/9/6
# Часть 3
f 7/41/3 8/42/3 16/48/3
f 7/41/3 16/48/3 15/47/3
f 15/17/2 16/18/2 12/24/2
f 15/17/2 12/24/2 11/23/2
f 11/29/7 12/30/7 4/36/7
f 11/29/7 4/36/7 3/35/7
f 3/5/6 4/6/6 8/12/6
f 3/5/6 8/12/6 7/11/6
g Ends1
f 1/49/3 5/51/3 13/52/3
f 1/49/3 13/52/3 9/50/3
f 4/49/1 12/50/1 16/52/1
f 4/49/1 16/52/1 8/51/1
g Sides2
# Часть 1
f 21/37/1 22/38/1 30/44/1
f 21/37/1 30/44/1 29/43/1
f 29/13/2 30/14/2 26/20/2
f 29/13/2 26/20/2 25/19/2
f 25/25/5 26/26/5 18/32/5
f 25/25/5 18/32/5 17/31/5
f 17/1/6 18/2/6 22/8/6
f 17/1/6 22/8/6 21/7/6
# Часть 2
f 22/39/4 23/40/4 31/46/4
f 22/39/4 31/46/4 30/45/4
f 30/15/2 31/16/2 27/22/2
f 30/15/2 27/22/2 26/21/2
f 26/27/8 27/28/8 19/34/8
f 26/27/8 19/34/8 18/33/8
f 18/3/6 19/4/6 23/10/6
f 18/3/6 23/10/6 22/9/6
# Часть 3
f 23/41/3 24/42/3 32/48/3
f 23/41/3 32/48/3 31/47/3
f 31/17/2 32/18/2 28/24/2
f 31/17/2 28/24/2 27/23/2
f 27/29/7 28/30/7 20/36/7
f 27/29/7 20/36/7 19/35/7
f 19/5/6 20/6/6 24/12/6
f 19/5/6 24/12/6 23/11/6
g Ends2
f 17/49/3 21/51/3 29/52/3
f 17/49/3 29/52/3 25/50/3
f 20/49/1 28/50/1 32/52/1
f 20/49/1 32/52/1 24/51/1

View File

@ -88,6 +88,7 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
minetest.register_craft({ minetest.register_craft({
output = "mesecons_extrawires:tjunction_off 3", output = "mesecons_extrawires:tjunction_off 3",
recipe = { recipe = {
{"", "", ""},
{"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"}, {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"},
{"", "mesecons_insulated:insulated_off", ""}, {"", "mesecons_insulated:insulated_off", ""},
} }

View File

@ -0,0 +1,2 @@
mesecons
screwdriver?

View File

@ -1,11 +1,10 @@
local plg = {} local plg = {}
plg.rules = {} plg.rules = {}
-- per-player formspec positions
plg.open_formspecs = {}
local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua") local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg) dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg)
plg.register_nodes = function(template) plg.register_nodes = function(template)
-- each loop is for one of the 4 IO ports -- each loop is for one of the 4 IO ports
for a = 0, 1 do for a = 0, 1 do
@ -94,20 +93,16 @@ plg.register_nodes({
meta:set_string("instr", lcore.serialize(is)) meta:set_string("instr", lcore.serialize(is))
meta:set_int("valid", 0) meta:set_int("valid", 0)
meta:set_string("formspec", plg.to_formspec_string(is))
meta:set_string("infotext", "FPGA") meta:set_string("infotext", "FPGA")
end, end,
on_rightclick = function(pos, node, clicker) on_receive_fields = function(pos, formname, fields, sender)
if not minetest.is_player(clicker) then if fields.program == nil then return end -- we only care when the user clicks "Program"
return
end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local name = clicker:get_player_name() local is = plg.from_formspec_fields(fields)
-- Erase formspecs of old FPGAs
meta:set_string("formspec", "")
plg.open_formspecs[name] = pos meta:set_string("instr", lcore.serialize(is))
local is = lcore.deserialize(meta:get_string("instr")) plg.update_formspec(pos, is)
minetest.show_formspec(name, "mesecons:fpga", plg.to_formspec_string(is, nil))
end, end,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = { mesecons = {
@ -121,12 +116,6 @@ plg.register_nodes({
}, },
after_dig_node = function(pos, node) after_dig_node = function(pos, node)
mesecon.receptor_off(pos, plg.rules[node.name]) 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, end,
on_blast = mesecon.on_blastnode, on_blast = mesecon.on_blastnode,
on_rotate = function(pos, node, user, mode) on_rotate = function(pos, node, user, mode)
@ -164,12 +153,13 @@ plg.register_nodes({
end end
meta:set_string("instr", lcore.serialize(instr)) meta:set_string("instr", lcore.serialize(instr))
plg.update_meta(pos, instr) plg.update_formspec(pos, instr)
return true return true
end, end,
}) })
plg.to_formspec_string = function(is, err)
plg.to_formspec_string = function(is)
local function dropdown_op(x, y, name, val) local function dropdown_op(x, y, name, val)
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored? .. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored?
@ -190,20 +180,26 @@ plg.to_formspec_string = function(is, err)
return s .. "]" return s .. "]"
end end
local function dropdown_action(x, y, name, val) local function dropdown_action(x, y, name, val)
local selected = 0 local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
local titles = { " " } .. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored?
for i, data in ipairs(lcore.get_operations()) do s = s .. " , AND, OR, NOT, XOR,NAND, =,XNOR;"
titles[i + 1] = data.fs_name if val == nil then
if val == data.gate then return s .. "0]" -- actually selects no field at all
selected = i + 1
end
end end
return ("dropdown[%f,%f;1.125,0.5;%s;%s;%i]"):format( local mapping = {
x, y, name, table.concat(titles, ","), selected) ["and"] = 1,
["or"] = 2,
["not"] = 3,
["xor"] = 4,
["nand"] = 5,
["buf"] = 6,
["xnor"] = 7,
}
return s .. tostring(1 + mapping[val]) .. "]"
end end
local s = "size[9,9]".. local s = "size[9,9]"..
"label[3.4,-0.15;FPGA gate configuration]".. "label[3.4,-0.15;FPGA gate configuration]"..
"button[7,7.5;2,2.5;program;Program]".. "button_exit[7,7.5;2,2.5;program;Program]"..
"box[4.2,0.5;0.03,7;#ffffff]".. "box[4.2,0.5;0.03,7;#ffffff]"..
"label[0.25,0.25;op. 1]".. "label[0.25,0.25;op. 1]"..
"label[1.0,0.25;gate type]".. "label[1.0,0.25;gate type]"..
@ -229,12 +225,6 @@ plg.to_formspec_string = function(is, err)
y = 1 - 0.25 y = 1 - 0.25
end end
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 return s
end end
@ -249,11 +239,20 @@ plg.from_formspec_fields = function(fields)
end end
end end
local function read_action(s) local function read_action(s)
for i, data in ipairs(lcore.get_operations()) do if s == nil or s == " " then
if data.fs_name == s then return nil
return data.gate
end
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 end
local is = {} local is = {}
for i = 1, 14 do for i = 1, 14 do
@ -267,11 +266,12 @@ plg.from_formspec_fields = function(fields)
return is return is
end end
plg.update_meta = function(pos, is) plg.update_formspec = function(pos, is)
if type(is) == "string" then -- serialized string if type(is) == "string" then -- serialized string
is = lcore.deserialize(is) is = lcore.deserialize(is)
end end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local form = plg.to_formspec_string(is)
local err = lcore.validate(is) local err = lcore.validate(is)
if err == nil then if err == nil then
@ -280,20 +280,17 @@ plg.update_meta = function(pos, is)
else else
meta:set_int("valid", 0) meta:set_int("valid", 0)
meta:set_string("infotext", "FPGA") 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 end
meta:set_string("formspec", form)
-- reset ports and run programmed logic -- reset ports and run programmed logic
plg.setports(pos, false, false, false, false) plg.setports(pos, false, false, false, false)
plg.update(pos) 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 end
plg.red_box_around = function(i) plg.red_box_around = function(i)
@ -412,38 +409,6 @@ plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
end 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({ minetest.register_craft({
output = "mesecons_fpga:fpga0000 2", output = "mesecons_fpga:fpga0000 2",

View File

@ -1,27 +1,5 @@
local lg = {} 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 -- (de)serialize
lg.serialize = function(t) lg.serialize = function(t)
local function _op(t) local function _op(t)
@ -33,14 +11,20 @@ lg.serialize = function(t)
return tostring(t.n) return tostring(t.n)
end end
end end
-- Serialize actions (gates) from eg. "and" to "&" local function _action(s)
local function _action(action) if s == nil then
for i, data in ipairs(operations) do return " "
if data.gate == action then
return data.short
end
end end
return " " local mapping = {
["and"] = "&",
["or"] = "|",
["not"] = "~",
["xor"] = "^",
["nand"] = "?", --dunno
["buf"] = "_",
["xnor"] = "=",
}
return mapping[s]
end end
local s = "" local s = ""
@ -64,14 +48,18 @@ lg.deserialize = function(s)
return {type = "reg", n = tonumber(c)} return {type = "reg", n = tonumber(c)}
end end
end end
-- Deserialize actions (gates) from eg. "&" to "and" local function _action(c)
local function _action(action) local mapping = {
for i, data in ipairs(operations) do ["&"] = "and",
if data.short == action then ["|"] = "or",
return data.gate ["~"] = "not",
end ["^"] = "xor",
end ["?"] = "nand",
-- nil ["_"] = "buf",
["="] = "xnor",
[" "] = nil,
}
return mapping[c]
end end
local ret = {} local ret = {}
@ -121,25 +109,16 @@ lg.validate_single = function(t, i)
return false return false
end end
local elem = t[i] 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 -- check for completeness
if not gate_data then if elem.action == nil then
return {i = i, msg = "Gate type is required"} return {i = i, msg = "Gate type required"}
elseif gate_data.unary then elseif elem.action == "not" or elem.action == "buf" then
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil 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"} return {i = i, msg = "Second operand (only) and destination required"}
end end
else else
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
return {i = i, msg = "Operands and destination are required"} return {i = i, msg = "Operands and destination required"}
end end
end end
-- check whether operands/destination are identical -- check whether operands/destination are identical
@ -180,12 +159,21 @@ end
-- interpreter -- interpreter
lg.interpret = function(t, a, b, c, d) lg.interpret = function(t, a, b, c, d)
local function _action(s, v1, v2) local function _action(s, v1, v2)
for i, data in ipairs(operations) do if s == "and" then
if data.gate == s then return v1 and v2
return data.func(v1, v2) elseif s == "or" then
end return v1 or v2
elseif s == "not" then
return not v2
elseif s == "xor" then
return v1 ~= v2
elseif s == "nand" then
return not (v1 and v2)
elseif s == "buf" then
return v2
else -- s == "xnor"
return v1 == v2
end end
return false -- unknown gate
end end
local function _op(t, regs, io_in) local function _op(t, regs, io_in)
if t.type == "reg" then if t.type == "reg" then

View File

@ -1,3 +0,0 @@
name = mesecons_fpga
depends = mesecons
optional_depends = screwdriver

View File

@ -18,12 +18,10 @@ minetest.register_tool("mesecons_fpga:programmer", {
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if meta:get_string("instr") == "//////////////" then if meta:get_string("instr") == "//////////////" then
minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.") minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.")
minetest.sound_play("mesecons_fpga_fail", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true)
return itemstack return itemstack
end end
itemstack:set_metadata(meta:get_string("instr")) itemstack:set_metadata(meta:get_string("instr"))
minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!") minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!")
minetest.sound_play("mesecons_fpga_copy", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true)
return itemstack return itemstack
end, end,
@ -36,24 +34,17 @@ minetest.register_tool("mesecons_fpga:programmer", {
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
return itemstack return itemstack
end 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() local imeta = itemstack:get_metadata()
if imeta == "" then if imeta == "" then
minetest.chat_send_player(player_name, "Use shift+right-click to copy a gate configuration first.") minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.")
minetest.sound_play("mesecons_fpga_fail", { pos = user:get_pos(), gain = 0.1, max_hear_distance = 4 }, true)
return itemstack return itemstack
end end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("instr", imeta) meta:set_string("instr", imeta)
plg.update_meta(pos, imeta) plg.update_formspec(pos, imeta)
minetest.chat_send_player(player_name, "Gate configuration was successfully written to FPGA!") minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!")
minetest.sound_play("mesecons_fpga_write", { pos = user:get_pos(), gain = 0.1, max_hear_distance = 4 }, true)
return itemstack return itemstack
end end

View File

@ -0,0 +1,6 @@
mesecons
mesecons_microcontroller
mesecons_delayer
mesecons_torch
mesecons_materials

View File

@ -1,14 +1,6 @@
local selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }
}
local nodebox = { local nodebox = {
type = "fixed", type = "fixed",
fixed = { fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }},
{ -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) local function gate_rotate_rules(node, rules)
@ -76,7 +68,7 @@ local function register_gate(name, inputnumber, assess, recipe, description)
is_ground_content = false, is_ground_content = false,
drawtype = "nodebox", drawtype = "nodebox",
drop = basename.."_off", drop = basename.."_off",
selection_box = selection_box, selection_box = nodebox,
node_box = nodebox, node_box = nodebox,
walkable = true, walkable = true,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
@ -86,16 +78,8 @@ local function register_gate(name, inputnumber, assess, recipe, description)
inputnumber = inputnumber, inputnumber = inputnumber,
after_dig_node = mesecon.do_cooldown, after_dig_node = mesecon.do_cooldown,
},{ },{
tiles = { tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^".. "jeija_gate_"..name..".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}, groups = {dig_immediate = 2, overheat = 1},
mesecons = { receptor = { mesecons = { receptor = {
state = "off", state = "off",
@ -105,16 +89,8 @@ local function register_gate(name, inputnumber, assess, recipe, description)
action_change = update_gate action_change = update_gate
}} }}
},{ },{
tiles = { tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^"..
"jeija_microcontroller_bottom.png^".."jeija_gate_on.png^".. "jeija_gate_"..name..".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}, groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1},
mesecons = { receptor = { mesecons = { receptor = {
state = "on", state = "on",

View File

@ -1,2 +0,0 @@
name = mesecons_gates
depends = mesecons, mesecons_microcontroller, mesecons_delayer, mesecons_torch, mesecons_materials

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 B

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_hydroturbine
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
screwdriver?

View File

@ -1,3 +0,0 @@
name = mesecons_insulated
depends = mesecons
optional_depends = screwdriver

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_lamp
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
dye

View File

@ -1,2 +0,0 @@
name = mesecons_lightstone
depends = mesecons, dye

View File

@ -0,0 +1 @@
mesecons

View File

@ -266,46 +266,6 @@ local function remove_functions(x)
return x return x
end end
local function validate_iid(iid)
if not iid then return true end -- nil is OK
local limit = mesecon.setting("luacontroller_interruptid_maxlen", 256)
if type(iid) == "string" then
if #iid <= limit then return true end -- string is OK unless too long
return false, "An interrupt ID was too large!"
end
if type(iid) == "number" or type(iid) == "boolean" then return true, "Non-string interrupt IDs are deprecated" end
local warn
local seen = {}
local function check(t)
if type(t) == "function" then
warn = "Functions cannot be used in interrupt IDs"
return false
end
if type(t) ~= "table" then
return true
end
if seen[t] then
warn = "Non-tree-like tables are forbidden as interrupt IDs"
return false
end
seen[t] = true
for k, v in pairs(t) do
if not check(k) then return false end
if not check(v) then return false end
end
return true
end
if not check(iid) then return false, warn end
if #minetest.serialize(iid) > limit then
return false, "An interrupt ID was too large!"
end
return true, "Table interrupt IDs are deprecated and are unreliable; use strings instead"
end
-- The setting affects API so is not intended to be changeable at runtime -- The setting affects API so is not intended to be changeable at runtime
local get_interrupt local get_interrupt
if mesecon.setting("luacontroller_lightweight_interrupts", false) then if mesecon.setting("luacontroller_lightweight_interrupts", false) then
@ -322,18 +282,26 @@ else
-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards -- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
get_interrupt = function(pos, itbl, send_warning) get_interrupt = function(pos, itbl, send_warning)
-- iid = interrupt id -- iid = interrupt id
return function (time, iid) local function interrupt(time, iid)
-- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y -- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
-- Hence the values get moved out. Should take less time than original, so totally compatible -- Hence the values get moved out. Should take less time than original, so totally compatible
if type(time) ~= "number" then error("Delay must be a number") end if type(time) ~= "number" then error("Delay must be a number") end
table.insert(itbl, function () table.insert(itbl, function ()
-- Outside string metatable sandbox, can safely run this now -- Outside string metatable sandbox, can safely run this now
local luac_id = minetest.get_meta(pos):get_int("luac_id") local luac_id = minetest.get_meta(pos):get_int("luac_id")
local ok, warn = validate_iid(iid) -- Check if IID is dodgy, so you can't use interrupts to store an infinite amount of data.
if ok then mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) end -- Note that this is safe from alter-after-free because this code gets run after the sandbox has ended.
if warn then send_warning(warn) end -- This runs outside of the timer and *shouldn't* harm perf. unless dodgy data is being sent in the first place
iid = remove_functions(iid)
local msg_ser = minetest.serialize(iid)
if #msg_ser <= mesecon.setting("luacontroller_interruptid_maxlen", 256) then
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1)
else
send_warning("An interrupt ID was too large!")
end
end) end)
end end
return interrupt
end end
end end
@ -664,7 +632,6 @@ local function reset_formspec(meta, code, errmsg)
code = minetest.formspec_escape(code or "") code = minetest.formspec_escape(code or "")
errmsg = minetest.formspec_escape(tostring(errmsg or "")) errmsg = minetest.formspec_escape(tostring(errmsg or ""))
meta:set_string("formspec", "size[12,10]" meta:set_string("formspec", "size[12,10]"
.."style_type[label,textarea;font=mono]"
.."background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]" .."background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]"
.."label[0.1,8.3;"..errmsg.."]" .."label[0.1,8.3;"..errmsg.."]"
.."textarea[0.2,0.2;12.2,9.5;code;;"..code.."]" .."textarea[0.2,0.2;12.2,9.5;code;;"..code.."]"
@ -934,3 +901,4 @@ minetest.register_craft({
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''},
} }
}) })

View File

@ -1,2 +0,0 @@
name = mesecons_luacontroller
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_materials
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_microcontroller
depends = mesecons

View File

@ -0,0 +1,3 @@
mesecons
mesecons_materials
mesecons_mvps

View File

@ -66,7 +66,6 @@ function mesecon.register_movestone(name, def, is_sticky, is_vertical)
mesecon.on_dignode(pos, node) mesecon.on_dignode(pos, node)
mesecon.on_placenode(frontpos, node) mesecon.on_placenode(frontpos, node)
minetest.get_node_timer(frontpos):start(timer_interval) minetest.get_node_timer(frontpos):start(timer_interval)
minetest.sound_play("movestone", { pos = pos, max_hear_distance = 20, gain = 0.5 }, true)
-- ### Step 3: If sticky, pull stack behind ### -- ### Step 3: If sticky, pull stack behind ###
if is_sticky then if is_sticky then

View File

@ -1,2 +0,0 @@
name = mesecons_movestones
depends = mesecons, mesecons_materials, mesecons_mvps

View File

@ -0,0 +1 @@
mesecons

View File

@ -163,7 +163,7 @@ local function add_pos(positions, pos)
end end
local function are_protected(positions, player_name) local function are_protected(positions, player_name)
local mode = mesecon.setting("mvps_protection_mode", "compat") local mode = mesecon.setting("mvps_protection_mode", "normal")
if mode == "ignore" then if mode == "ignore" then
return false return false
end end
@ -285,7 +285,7 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor)
end end
movefactor = movefactor or 1 movefactor = movefactor or 1
dir = vector.multiply(dir, movefactor) dir = vector.multiply(dir, movefactor)
for id, obj in pairs(minetest.get_objects_inside_radius(pos, #nodestack + 1)) do for id, obj in pairs(minetest.object_refs) do
local obj_pos = obj:get_pos() local obj_pos = obj:get_pos()
local cbox = obj:get_properties().collisionbox local cbox = obj:get_properties().collisionbox
local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3])) local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3]))

View File

@ -1,2 +0,0 @@
name = mesecons_mvps
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,13 +1,12 @@
This effector makes a sound if powered and can be used for making music. Normally it makes piano sounds. The sound frequency can be changed by punching the block (only works for piano). There are some special sounds that depend on the block below: This effector makes a sound if powered and can be used for making music. Normally it makes piano sounds. The sound frequency can be changed by punching the block. There are some special sounds that depend on the block below:
<table colspace="5"> <table colspace="5">
<tr><th>Block Below</th><th>Effect</th></tr> <tr><th>Block Below</th><th>Effect</th></tr>
<tr><td>Glass or Obsidian Glass</td><td>Hi-hat</td></tr> <tr><td>Glass</td><td>Hihat</td></tr>
<tr><td>Any stone</td><td>Kick</td></tr> <tr><td>Stone</td><td>Kick</td></tr>
<tr><td>Chest or Locked Chest</td><td>Snare</td></tr> <tr><td>Chest</td><td>Snare</td></tr>
<tr><td>Any tree</td><td>Crash</td></tr> <tr><td>Tree</td><td>Crash</td></tr>
<tr><td>Any wooden planks</td><td>Lite Crash</td></tr> <tr><td>Wood</td><td>Lite Crash</td></tr>
<tr><td>Coal Block</td><td>Explosion sound</td></tr> <tr><td>Coal Block</td><td>Explosion Sound </td></tr>
<tr><td>Lava Source</td><td>Fire sound</td></tr> <tr><td>Lava Source</td><td>Fire Sound</td></tr>
<tr><td>Steel Block</td><td>Piano (high pitch, one octave higher than normal)</td></tr> <tr><td>Steel Block</td><td>Raises the pitch by one octave</td></tr>
<tr><td>Any other block</td><td>Piano (low pitch)</td></tr>
</table> </table>

View File

@ -3,11 +3,7 @@ minetest.register_node("mesecons_noteblock:noteblock", {
tiles = {"mesecons_noteblock.png"}, tiles = {"mesecons_noteblock.png"},
is_ground_content = false, is_ground_content = false,
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
on_punch = function(pos, node, puncher) -- change sound when punched on_punch = function(pos, node) -- change sound when punched
if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then
return
end
node.param2 = (node.param2+1)%12 node.param2 = (node.param2+1)%12
mesecon.noteblock_play(pos, node.param2) mesecon.noteblock_play(pos, node.param2)
minetest.set_node(pos, node) minetest.set_node(pos, node)
@ -47,33 +43,19 @@ local soundnames = {
} }
local node_sounds = { local node_sounds = {
["default:glass"] = "mesecons_noteblock_hihat",
["default:stone"] = "mesecons_noteblock_kick",
["default:lava_source"] = "fire_fire", ["default:lava_source"] = "fire_fire",
["default:chest"] = "mesecons_noteblock_snare", ["default:chest"] = "mesecons_noteblock_snare",
["default:chest_locked"] = "mesecons_noteblock_snare", ["default:tree"] = "mesecons_noteblock_crash",
["default:wood"] = "mesecons_noteblock_litecrash",
["default:coalblock"] = "tnt_explode", ["default:coalblock"] = "tnt_explode",
["default:glass"] = "mesecons_noteblock_hihat",
["default:obsidian_glass"] = "mesecons_noteblock_hihat",
}
local node_sounds_group = {
["stone"] = "mesecons_noteblock_kick",
["tree"] = "mesecons_noteblock_crash",
["wood"] = "mesecons_noteblock_litecrash",
} }
mesecon.noteblock_play = function(pos, param2) mesecon.noteblock_play = function(pos, param2)
pos.y = pos.y-1 pos.y = pos.y-1
local nodeunder = minetest.get_node(pos).name local nodeunder = minetest.get_node(pos).name
local soundname = node_sounds[nodeunder] local soundname = node_sounds[nodeunder]
if not soundname then
for k,v in pairs(node_sounds_group) do
local g = minetest.get_item_group(nodeunder, k)
if g ~= 0 then
soundname = v
break
end
end
end
if not soundname then if not soundname then
soundname = soundnames[param2] soundname = soundnames[param2]
if not soundname then if not soundname then
@ -85,11 +67,5 @@ mesecon.noteblock_play = function(pos, param2)
end end
end end
pos.y = pos.y+1 pos.y = pos.y+1
if soundname == "fire_fire" then minetest.sound_play(soundname, {pos = pos})
-- Smoothly fade out fire sound
local handle = minetest.sound_play(soundname, {pos = pos, loop = true})
minetest.after(3.0, minetest.sound_fade, handle, -1.5, 0.0)
else
minetest.sound_play(soundname, {pos = pos}, true)
end
end end

View File

@ -1,2 +0,0 @@
name = mesecons_noteblock
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
mesecons_mvps

View File

@ -67,7 +67,11 @@ local function piston_remove_pusher(pos, node, check_falling)
end end
minetest.remove_node(pusherpos) minetest.remove_node(pusherpos)
minetest.sound_play("piston_retract", { pos = pos, max_hear_distance = 20, gain = 0.3 }, true) minetest.sound_play("piston_retract", {
pos = pos,
max_hear_distance = 20,
gain = 0.3,
})
if check_falling then if check_falling then
minetest.check_for_falling(pusherpos) minetest.check_for_falling(pusherpos)
@ -92,7 +96,11 @@ local piston_on = function(pos, node)
end end
minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname}) minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname})
minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher}) minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher})
minetest.sound_play("piston_extend", { pos = pos, max_hear_distance = 20, gain = 0.3 }, true) minetest.sound_play("piston_extend", {
pos = pos,
max_hear_distance = 20,
gain = 0.3,
})
mesecon.mvps_process_stack(stack) mesecon.mvps_process_stack(stack)
mesecon.mvps_move_objects(pusher_pos, dir, oldstack) mesecon.mvps_move_objects(pusher_pos, dir, oldstack)
end end

View File

@ -1,2 +0,0 @@
name = mesecons_pistons
depends = mesecons, mesecons_mvps

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_powerplant
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -24,7 +24,7 @@ local function pp_on_timer(pos, elapsed)
mesecon.receptor_off(pos, mesecon.rules.pplate) mesecon.receptor_off(pos, mesecon.rules.pplate)
elseif node.name == basename .. "_off" then elseif node.name == basename .. "_off" then
for k, obj in pairs(objs) do for k, obj in pairs(objs) do
local objpos = obj:get_pos() local objpos = obj:getpos()
if objpos.y > pos.y-1 and objpos.y < pos.y then if objpos.y > pos.y-1 and objpos.y < pos.y then
minetest.set_node(pos, {name = basename .. "_on"}) minetest.set_node(pos, {name = basename .. "_on"})
mesecon.receptor_on(pos, mesecon.rules.pplate ) mesecon.receptor_on(pos, mesecon.rules.pplate )

View File

@ -1,2 +0,0 @@
name = mesecons_pressureplates
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_random
depends = mesecons

View File

@ -0,0 +1 @@
mesecons

View File

@ -1,2 +0,0 @@
name = mesecons_receiver
depends = mesecons

View File

@ -0,0 +1,2 @@
mesecons
mesecons_materials

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,60 +1,98 @@
-- Solar Panel -- Solar Panel
mesecon.register_node("mesecons_solarpanel:solar_panel", { minetest.register_node("mesecons_solarpanel:solar_panel_on", {
description = "Solar Panel",
drawtype = "nodebox", drawtype = "nodebox",
tiles = {"mesecons_solarpanel.png"}, tiles = { "jeija_solar_panel.png", },
inventory_image = "mesecons_solarpanel.png", inventory_image = "jeija_solar_panel.png",
wield_image = "mesecons_solarpanel.png", wield_image = "jeija_solar_panel.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
walkable = false, walkable = false,
is_ground_content = false, is_ground_content = false,
node_box = { node_box = {
type = "wallmounted", type = "wallmounted",
wall_bottom = {-7/16, -8/16, -7/16, 7/16, -7/16, 7/16}, wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 },
wall_top = {-7/16, 7/16, -7/16, 7/16, 8/16, 7/16}, wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 },
wall_side = {-8/16, -7/16, -7/16, -7/16, 7/16, 7/16}, wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 },
}, },
selection_box = {
type = "wallmounted",
wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 },
wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 },
wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 },
},
drop = "mesecons_solarpanel:solar_panel_off",
groups = {dig_immediate=3, not_in_creative_inventory = 1},
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
on_blast = mesecon.on_blastnode,
},{
groups = {dig_immediate = 3},
mesecons = {receptor = {
state = mesecon.state.off,
rules = mesecon.rules.wallmounted_get
}}
},{
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.on, state = mesecon.state.on,
rules = mesecon.rules.wallmounted_get rules = mesecon.rules.wallmounted_get,
}}, }},
on_blast = mesecon.on_blastnode,
})
-- Solar Panel
minetest.register_node("mesecons_solarpanel:solar_panel_off", {
drawtype = "nodebox",
tiles = { "jeija_solar_panel.png", },
inventory_image = "jeija_solar_panel.png",
wield_image = "jeija_solar_panel.png",
paramtype = "light",
paramtype2 = "wallmounted",
walkable = false,
is_ground_content = false,
node_box = {
type = "wallmounted",
wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 },
wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 },
wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 },
},
selection_box = {
type = "wallmounted",
wall_bottom = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 },
wall_top = { -7/16, 7/16, -7/16, 7/16, 8/16, 7/16 },
wall_side = { -8/16, -7/16, -7/16, -7/16, 7/16, 7/16 },
},
groups = {dig_immediate=3},
description = "Solar Panel",
sounds = default.node_sound_glass_defaults(),
mesecons = {receptor = {
state = mesecon.state.off,
rules = mesecon.rules.wallmounted_get,
}},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({
output = "mesecons_solarpanel:solar_panel_off", output = "mesecons_solarpanel:solar_panel_off 1",
recipe = { recipe = {
{"mesecons_materials:silicon", "mesecons_materials:silicon"}, {"mesecons_materials:silicon", "mesecons_materials:silicon"},
{"mesecons_materials:silicon", "mesecons_materials:silicon"}, {"mesecons_materials:silicon", "mesecons_materials:silicon"},
} }
}) })
minetest.register_abm({ minetest.register_abm(
label = "Solar Panel On/Off", {nodenames = {"mesecons_solarpanel:solar_panel_off"},
nodenames = {
"mesecons_solarpanel:solar_panel_off",
"mesecons_solarpanel:solar_panel_on"
},
interval = 1, interval = 1,
chance = 1, chance = 1,
catch_up = false, action = function(pos, node, active_object_count, active_object_count_wider)
action = function(pos, node) local light = minetest.get_node_light(pos, nil)
local light = minetest.get_node_light(pos)
if light >= 12 and node.name == "mesecons_solarpanel:solar_panel_off" then if light >= 12 then
node.name = "mesecons_solarpanel:solar_panel_on" node.name = "mesecons_solarpanel:solar_panel_on"
minetest.swap_node(pos, node) minetest.swap_node(pos, node)
mesecon.receptor_on(pos, mesecon.rules.wallmounted_get(node)) mesecon.receptor_on(pos, mesecon.rules.wallmounted_get(node))
elseif light < 12 and node.name == "mesecons_solarpanel:solar_panel_on" then end
end,
})
minetest.register_abm(
{nodenames = {"mesecons_solarpanel:solar_panel_on"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local light = minetest.get_node_light(pos, nil)
if light < 12 then
node.name = "mesecons_solarpanel:solar_panel_off" node.name = "mesecons_solarpanel:solar_panel_off"
minetest.swap_node(pos, node) minetest.swap_node(pos, node)
mesecon.receptor_off(pos, mesecon.rules.wallmounted_get(node)) mesecon.receptor_off(pos, mesecon.rules.wallmounted_get(node))

View File

@ -1,2 +0,0 @@
name = mesecons_solarpanel
depends = mesecons, mesecons_materials

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

View File

@ -0,0 +1,2 @@
mesecons
mesecons_mvps

Some files were not shown because too many files have changed in this diff Show More