Merge remote-tracking branch 'upstream/master'

This commit is contained in:
bri cassa 2023-06-07 21:46:50 +02:00
commit ec3218d6d9
115 changed files with 2099 additions and 88 deletions

View File

@ -13,3 +13,29 @@ jobs:
run: luarocks install --local luacheck
- name: luacheck run
run: $HOME/.luarocks/bin/luacheck ./
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: apt
run: sudo apt-get install -y luarocks
- name: busted install
run: luarocks install --local busted
- name: luacov install
run: luarocks install --local luacov
- name: mineunit install
run: luarocks install --server=https://luarocks.org/dev --local mineunit
- name: run mesecons tests
working-directory: ./mesecons/
run: $HOME/.luarocks/bin/mineunit -q
- name: run mesecons_mvps tests
working-directory: ./mesecons_mvps/
run: $HOME/.luarocks/bin/mineunit -q
- name: run mesecons_fpga tests
working-directory: ./mesecons_fpga/
run: $HOME/.luarocks/bin/mineunit -q
- name: run mesecons_luacontroller tests
working-directory: ./mesecons_luacontroller/
run: $HOME/.luarocks/bin/mineunit -q

View File

@ -34,3 +34,26 @@ globals = {"mesecon"}
files["mesecons/actionqueue.lua"] = {
globals = {"minetest.registered_globalsteps"},
}
-- Test-specific stuff follows.
local test_conf = {
read_globals = {
"assert",
"fixture",
"mineunit",
"Player",
"sourcefile",
"world",
},
}
files["*/spec/*.lua"] = test_conf
files[".test_fixtures/*.lua"] = test_conf
files[".test_fixtures/screwdriver.lua"] = {
globals = {"screwdriver"},
}
files[".test_fixtures/mesecons_fpga.lua"] = {
globals = {"minetest.register_on_player_receive_fields"},
}

156
.test_fixtures/mesecons.lua Normal file
View File

@ -0,0 +1,156 @@
mineunit("core")
mineunit("server")
mineunit("voxelmanip")
mineunit:set_current_modname("mesecons")
mineunit:set_modpath("mesecons", "../mesecons")
sourcefile("../mesecons/init")
-- Utility node: this conductor is used to test the connectivity and state of adjacent wires.
do
local off_spec = {conductor = {
state = mesecon.state.off,
rules = mesecon.rules.alldirs,
onstate = "mesecons:test_conductor_on",
}}
local on_spec = {conductor = {
state = mesecon.state.on,
rules = mesecon.rules.alldirs,
offstate = "mesecons:test_conductor_off",
}}
mesecon.register_node("mesecons:test_conductor", {
description = "Test Conductor",
}, {mesecons = off_spec}, {mesecons = on_spec})
end
-- Utility node: this receptor is used to test power sources.
do
local off_spec = {receptor = {
state = mesecon.state.off,
rules = mesecon.rules.alldirs,
}}
local on_spec = {receptor = {
state = mesecon.state.on,
rules = mesecon.rules.alldirs,
}}
mesecon.register_node("mesecons:test_receptor", {
description = "Test Receptor",
}, {mesecons = off_spec}, {mesecons = on_spec})
end
-- Utility node: this effector is used to test circuit outputs.
do
-- This is a list of actions in the form {<kind>, <pos>},
-- where <kind> is "on", "off", or "overheat".
mesecon._test_effector_events = {}
local function action_on(pos, node)
table.insert(mesecon._test_effector_events, {"on", pos})
node.param2 = node.param2 % 64 + 128 -- Turn on bit 7
minetest.swap_node(pos, node)
end
local function action_off(pos, node)
table.insert(mesecon._test_effector_events, {"off", pos})
node.param2 = node.param2 % 64 -- Turn off bit 7
minetest.swap_node(pos, node)
end
local function action_change(pos, node, rule_name, new_state)
if mesecon.do_overheat(pos) then
table.insert(mesecon._test_effector_events, {"overheat", pos})
minetest.remove_node(pos)
return
end
-- Set the value of a bit in param2 according to the rule name and new state.
local bit = tonumber(rule_name.name, 2)
local bits_above = node.param2 - node.param2 % (bit * 2)
local bits_below = node.param2 % bit
local bits_flipped = new_state == mesecon.state.on and bit or 0
node.param2 = bits_above + bits_flipped + bits_below
minetest.swap_node(pos, node)
end
minetest.register_node("mesecons:test_effector", {
description = "Test Effector",
mesecons = {effector = {
action_on = action_on,
action_off = action_off,
action_change = action_change,
rules = {
{x = 1, y = 0, z = 0, name = "000001"},
{x = -1, y = 0, z = 0, name = "000010"},
{x = 0, y = 1, z = 0, name = "000100"},
{x = 0, y = -1, z = 0, name = "001000"},
{x = 0, y = 0, z = 1, name = "010000"},
{x = 0, y = 0, z = -1, name = "100000"},
}
}},
})
end
-- Utility node: this conductor is used to test rotation.
do
local get_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}, {x = -1, y = 0, z = 0}})
local off_spec = {conductor = {
state = mesecon.state.off,
rules = get_rules,
onstate = "mesecons:test_conductor_rot_on",
}}
local on_spec = {conductor = {
state = mesecon.state.on,
rules = get_rules,
offstate = "mesecons:test_conductor_rot_off",
}}
mesecon.register_node("mesecons:test_conductor_rot", {
description = "Rotatable Test Conductor",
on_rotate = mesecon.on_rotate_horiz,
}, {mesecons = off_spec}, {mesecons = on_spec})
end
-- Utility node: this is used to test multiple conductors within a single node.
do
local mesecons_spec = {conductor = {
rules = {
{{x = 1, y = 0, z = 0}, {x = 0, y = -1, z = 0}},
{{x = 0, y = 1, z = 0}, {x = 0, y = 0, z = -1}},
{{x = 0, y = 0, z = 1}, {x = -1, y = 0, z = 0}},
},
states = {
"mesecons:test_multiconductor_off", "mesecons:test_multiconductor_001",
"mesecons:test_multiconductor_010", "mesecons:test_multiconductor_011",
"mesecons:test_multiconductor_100", "mesecons:test_multiconductor_101",
"mesecons:test_multiconductor_110", "mesecons:test_multiconductor_on",
},
}}
for _, state in ipairs(mesecons_spec.conductor.states) do
minetest.register_node(state, {
description = "Test Multiconductor",
mesecons = mesecons_spec,
})
end
end
mesecon._test_autoconnects = {}
mesecon.register_autoconnect_hook("test", function(pos, node)
table.insert(mesecon._test_autoconnects, {pos, node})
end)
function mesecon._test_dig(pos)
local node = minetest.get_node(pos)
minetest.remove_node(pos)
mesecon.on_dignode(pos, node)
end
function mesecon._test_place(pos, node)
world.set_node(pos, node)
mesecon.on_placenode(pos, minetest.get_node(pos))
end
function mesecon._test_reset()
-- First let circuits settle by simulating many globalsteps.
for i = 1, 10 do
mineunit:execute_globalstep(60)
end
mesecon.queue.actions = {}
mesecon._test_effector_events = {}
mesecon._test_autoconnects = {}
end
mineunit:execute_globalstep(mesecon.setting("resumetime", 4) + 1)

View File

@ -0,0 +1,59 @@
mineunit("player")
fixture("mesecons")
fixture("mesecons_gamecompat")
local registered_on_player_receive_fields = {}
local old_register_on_player_receive_fields = minetest.register_on_player_receive_fields
function minetest.register_on_player_receive_fields(func)
old_register_on_player_receive_fields(func)
table.insert(registered_on_player_receive_fields, func)
end
mineunit:set_current_modname("mesecons_fpga")
mineunit:set_modpath("mesecons_fpga", "../mesecons_fpga")
sourcefile("../mesecons_fpga/init")
local fpga_user = Player("mesecons_fpga_user")
function mesecon._test_program_fpga(pos, program)
local node = minetest.get_node(pos)
assert.equal("mesecons_fpga:fpga", node.name:sub(1, 18))
local fields = {program = true}
for i, instr in ipairs(program) do
-- Translate the instruction into formspec fields.
local op1, act, op2, dst
if #instr == 3 then
act, op2, dst = unpack(instr)
else
assert.equal(4, #instr)
op1, act, op2, dst = unpack(instr)
end
fields[i .. "op1"] = op1
fields[i .. "act"] = (" "):rep(4 - #act) .. act
fields[i .. "op2"] = op2
fields[i .. "dst"] = dst
end
minetest.registered_nodes[node.name].on_rightclick(pos, node, fpga_user)
for _, func in ipairs(registered_on_player_receive_fields) do
if func(fpga_user, "mesecons:fpga", fields) then
break
end
end
end
function mesecon._test_copy_fpga_program(pos)
fpga_user:get_inventory():set_stack("main", 1, "mesecons_fpga:programmer")
local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)}
fpga_user:do_place(pt)
return fpga_user:get_wielded_item()
end
function mesecon._test_paste_fpga_program(pos, tool)
fpga_user:get_inventory():set_stack("main", 1, tool)
local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)}
fpga_user:do_use(pt)
end

View File

@ -0,0 +1,5 @@
fixture("mesecons")
mineunit:set_current_modname("mesecons_gamecompat")
mineunit:set_modpath("mesecons_gamecompat", "../mesecons_gamecompat")
sourcefile("../mesecons_gamecompat/init")

View File

@ -0,0 +1,12 @@
fixture("mesecons")
fixture("mesecons_gamecompat")
mineunit:set_current_modname("mesecons_luacontroller")
mineunit:set_modpath("mesecons_luacontroller", "../mesecons_luacontroller")
sourcefile("../mesecons_luacontroller/init")
function mesecon._test_program_luac(pos, code)
local node = minetest.get_node(pos)
assert.equal("mesecons_luacontroller:luacontroller", node.name:sub(1, 36))
return minetest.registered_nodes[node.name].mesecons.luacontroller.set_program(pos, code)
end

View File

@ -0,0 +1,45 @@
mineunit("protection")
fixture("mesecons")
mineunit:set_current_modname("mesecons_mvps")
mineunit:set_modpath("mesecons_mvps", "../mesecons_mvps")
sourcefile("../mesecons_mvps/init")
minetest.register_node("mesecons_mvps:test_stopper", {
description = "Test Stopper",
})
mesecon.register_mvps_stopper("mesecons_mvps:test_stopper")
minetest.register_node("mesecons_mvps:test_stopper_cond", {
description = "Test Stopper (Conditional)",
})
mesecon.register_mvps_stopper("mesecons_mvps:test_stopper_cond", function(node)
return node.param2 == 0
end)
minetest.register_node("mesecons_mvps:test_sticky", {
description = "Test Sticky",
mvps_sticky = function(pos)
local connected = {}
for i, rule in ipairs(mesecon.rules.alldirs) do
connected[i] = vector.add(pos, rule)
end
return connected
end,
})
mesecon._test_moves = {}
minetest.register_node("mesecons_mvps:test_on_move", {
description = "Test Moveable",
mesecon = {
on_mvps_move = function(pos, node, oldpos, meta)
table.insert(mesecon._test_moves, {pos, node, oldpos, meta})
end
},
})
local old_reset = mesecon._test_reset
function mesecon._test_reset()
mesecon._test_moves = {}
old_reset()
end

View File

@ -0,0 +1,6 @@
mineunit:set_current_modname("screwdriver")
screwdriver = {}
screwdriver.ROTATE_FACE = 1
screwdriver.ROTATE_AXIS = 2

View File

@ -99,7 +99,6 @@ mesecon.queue:add_function("receptor_off", function (pos, rules)
local rulenames = mesecon.rules_link_rule_all(pos, rule)
for _, rulename in ipairs(rulenames) do
mesecon.vm_begin()
mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
-- Turnoff returns true if turnoff process was successful, no onstate receptor
-- was found along the way. Commit changes that were made in voxelmanip. If turnoff
@ -118,8 +117,6 @@ function mesecon.receptor_off(pos, rules)
end
print("[OK] Mesecons")
-- Deprecated stuff
-- To be removed in future releases
dofile(minetest.get_modpath("mesecons").."/legacy.lua");

View File

@ -542,9 +542,12 @@ function mesecon.turnoff(pos, link)
end
for _, sig in ipairs(signals) do
mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth)
if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then
mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth)
-- If sig.depth is 1, it has not yet been checked that the power source is actually off.
if sig.depth > 1 or not mesecon.is_powered(sig.pos, sig.link) then
mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth)
if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then
mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth)
end
end
end

View File

@ -0,0 +1,4 @@
# textdomain: mesecons
### oldwires.lua ###
Mesecons=Mesekonduktilo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons
### oldwires.lua ###
Mesecons=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_node("mesecons:mesecon_off", {
drawtype = "raillike",
tiles = {"jeija_mesecon_off.png", "jeija_mesecon_curved_off.png", "jeija_mesecon_t_junction_off.png", "jeija_mesecon_crossing_off.png"},
@ -11,7 +13,7 @@ minetest.register_node("mesecons:mesecon_off", {
fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5},
},
groups = {dig_immediate=3, mesecon=1, mesecon_conductor_craftable=1},
description="Mesecons",
description= S("Mesecons"),
mesecons = {conductor={
state = mesecon.state.off,
onstate = "mesecons:mesecon_on"

View File

@ -64,6 +64,8 @@ local rules_buttonlike = {
}
local function rules_from_dir(ruleset, dir)
if not dir then return {} end
if dir.x == 1 then return ruleset.xp end
if dir.y == 1 then return ruleset.yp end
if dir.z == 1 then return ruleset.zp end

View File

@ -0,0 +1,62 @@
require("mineunit")
fixture("mesecons")
describe("action queue", function()
local layout = {
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"},
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_off"},
{{x = 0, y = 1, z = 0}, "mesecons:test_effector"},
{{x = -1, y = 1, z = 0}, "mesecons:test_effector"},
}
before_each(function()
world.layout(layout)
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("executes in order", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal(2, #mesecon._test_effector_events)
assert.same({"on", layout[4][1]}, mesecon._test_effector_events[1])
assert.same({"on", layout[5][1]}, mesecon._test_effector_events[2])
world.set_node(layout[1][1], "mesecons:test_receptor_off")
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_off action
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal(4, #mesecon._test_effector_events)
assert.same({"off", layout[4][1]}, mesecon._test_effector_events[3])
assert.same({"off", layout[5][1]}, mesecon._test_effector_events[4])
end)
it("discards outdated/overwritten node events", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
world.set_node(layout[1][1], "mesecons:test_receptor_off")
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_off action
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal(0, #mesecon._test_effector_events)
end)
it("delays actions", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.queue:add_action(layout[1][1], "receptor_on", {mesecon.rules.alldirs}, 1, nil)
mineunit:execute_globalstep(0.1)
mineunit:execute_globalstep(1)
assert.equal(0, #mesecon._test_effector_events)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal(0, #mesecon._test_effector_events)
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal(2, #mesecon._test_effector_events)
end)
end)

View File

@ -0,0 +1 @@
fixture_paths = {"../.test_fixtures"}

View File

@ -0,0 +1,192 @@
require("mineunit")
fixture("mesecons")
fixture("screwdriver")
describe("placement/digging service", function()
local layout = {
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"},
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_on"},
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"},
{{x = 0, y = 1, z = 0}, "mesecons:test_effector"},
{{x = -2, y = 0, z = 0}, "mesecons:test_effector"},
{{x = 2, y = 0, z = 0}, "mesecons:test_effector"},
}
before_each(function()
world.layout(layout)
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("updates components when a receptor changes", function()
-- Dig then replace a receptor and check that the connected effectors changed.
mesecon._test_dig(layout[1][1])
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_off", world.get_node(layout[2][1]).name)
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal(3, #mesecon._test_effector_events)
mesecon._test_place(layout[1][1], "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name)
mineunit:execute_globalstep() -- Execute activate/change action
assert.equal(6, #mesecon._test_effector_events)
end)
it("updates components when a conductor changes", function()
-- Dig then replace a powered conductor and check that the connected effectors changed.
mesecon._test_dig(layout[2][1])
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal(2, #mesecon._test_effector_events)
mesecon._test_place(layout[2][1], "mesecons:test_conductor_off")
assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name)
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal(4, #mesecon._test_effector_events)
end)
it("updates effectors on placement", function()
local pos = {x = 0, y = 0, z = 1}
mesecon._test_place(pos, "mesecons:test_effector")
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal(tonumber("10100000", 2), world.get_node(pos).param2)
end)
it("updates multiconductors on placement", function()
local pos = {x = 0, y = 0, z = 1}
mesecon._test_place(pos, "mesecons:test_multiconductor_off")
assert.equal("mesecons:test_multiconductor_010", world.get_node(pos).name)
end)
it("turns off conductors on placement", function()
local pos = {x = 3, y = 0, z = 0}
mesecon._test_place(pos, "mesecons:test_conductor_on")
assert.equal("mesecons:test_conductor_off", world.get_node(pos).name)
end)
it("turns off multiconductors on placement", function()
local pos = {x = 3, y = 0, z = 0}
mesecon._test_place(pos, "mesecons:test_multiconductor_on")
assert.equal("mesecons:test_multiconductor_off", world.get_node(pos).name)
end)
it("triggers autoconnect hooks", function()
mesecon._test_dig(layout[2][1])
mineunit:execute_globalstep() -- Execute delayed hook
assert.equal(1, #mesecon._test_autoconnects)
mesecon._test_place(layout[2][1], layout[2][2])
assert.equal(2, #mesecon._test_autoconnects)
end)
end)
describe("overheating service", function()
local layout = {
{{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"},
{{x = 1, y = 0, z = 0}, "mesecons:test_effector"},
{{x = 2, y = 0, z = 0}, "mesecons:test_receptor_on"},
}
before_each(function()
world.layout(layout)
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("tracks heat", function()
mesecon.do_overheat(layout[2][1])
assert.equal(1, mesecon.get_heat(layout[2][1]))
mesecon.do_cooldown(layout[2][1])
assert.equal(0, mesecon.get_heat(layout[2][1]))
end)
it("cools over time", function()
mesecon.do_overheat(layout[2][1])
assert.equal(1, mesecon.get_heat(layout[2][1]))
mineunit:execute_globalstep(60)
mineunit:execute_globalstep(60)
mineunit:execute_globalstep(60)
assert.equal(0, mesecon.get_heat(layout[2][1]))
end)
it("tracks movement", function()
local oldpos = layout[2][1]
local pos = vector.offset(oldpos, 0, 1, 0)
mesecon.do_overheat(oldpos)
mesecon.move_hot_nodes({{pos = pos, oldpos = oldpos}})
assert.equal(0, mesecon.get_heat(oldpos))
assert.equal(1, mesecon.get_heat(pos))
end)
it("causes overheating", function()
-- Switch the first receptor on and off until it overheats/breaks a receptor.
repeat
if mesecon.flipstate(layout[1][1], minetest.get_node(layout[1][1])) == "on" then
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
else
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
end
mineunit:execute_globalstep(0) -- Execute receptor_on/receptor_off/activate/deactivate/change actions
until minetest.get_node(layout[2][1]).name ~= "mesecons:test_effector"
assert.same({"overheat", layout[2][1]}, mesecon._test_effector_events[#mesecon._test_effector_events])
assert.equal(0, mesecon.get_heat(layout[2][1]))
end)
end)
describe("screwdriver service", function()
local layout = {
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_rot_on"},
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"},
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"},
{{x = 0, y = 0, z = 1}, "mesecons:test_receptor_on"},
{{x = 0, y = 0, z = -1}, "mesecons:test_conductor_off"},
}
local function rotate(new_param2)
local pos = layout[1][1]
local node = world.get_node(pos)
local on_rotate = minetest.registered_nodes[node.name].on_rotate
on_rotate(pos, node, nil, screwdriver.ROTATE_FACE, new_param2)
end
before_each(function()
world.layout(layout)
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("updates conductors", function()
-- Rotate a conductor and see that the circuit state changes.
rotate(1)
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name)
rotate(2)
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name)
rotate(3)
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name)
rotate(0)
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name)
end)
end)

View File

@ -0,0 +1,147 @@
require("mineunit")
fixture("mesecons")
describe("state", function()
local layout = {
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
{{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"},
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"},
{{x = -1, y = 0, z = 0}, "mesecons:test_effector"},
{{x = 2, y = 0, z = 0}, "mesecons:test_effector"},
{{x = 0, y = -1, z = 0}, "mesecons:test_effector"},
}
before_each(function()
world.layout(layout)
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("turns on", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2)
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
world.set_node(layout[2][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2)
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
end)
it("turns off", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
world.set_node(layout[2][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on actions
world.set_node(layout[1][1], "mesecons:test_receptor_off")
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_off and activate/change actions
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2)
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
world.set_node(layout[2][1], "mesecons:test_receptor_off")
mesecon.receptor_off(layout[2][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_off action
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
assert.equal(tonumber("00000000", 2), world.get_node(layout[4][1]).param2)
assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2)
assert.equal(tonumber("00000000", 2), world.get_node(layout[6][1]).param2)
end)
end)
describe("rotation", function()
local layout = {
{{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"},
{{x = 1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 0}},
{{x = 0, y = 0, z = 1}, {name = "mesecons:test_conductor_rot_off", param2 = 1}},
{{x = -1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 2}},
{{x = 0, y = 0, z = -1}, {name = "mesecons:test_conductor_rot_off", param2 = 3}},
}
before_each(function()
for _, entry in ipairs(layout) do
world.set_node(entry[1], entry[2])
end
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("works", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[2][1]).name)
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[3][1]).name)
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[4][1]).name)
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[5][1]).name)
end)
end)
describe("multiconductor", function()
local layout = {
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
{{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"},
{{x = 0, y = 0, z = 1}, "mesecons:test_receptor_off"},
{{x = 0, y = 0, z = 0}, "mesecons:test_multiconductor_off"},
}
before_each(function()
world.layout(layout)
end)
after_each(function()
world.clear()
mesecon._test_reset()
end)
it("separates its subparts", function()
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_multiconductor_001", world.get_node(layout[4][1]).name)
world.set_node(layout[2][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_multiconductor_011", world.get_node(layout[4][1]).name)
world.set_node(layout[3][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[3][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_multiconductor_on", world.get_node(layout[4][1]).name)
end)
it("loops through itself", function()
-- Make a loop.
world.set_node({x = 0, y = -1, z = 0}, "mesecons:test_conductor_off")
world.set_node({x = -1, y = -1, z = 0}, "mesecons:test_conductor_off")
world.set_node({x = -1, y = 0, z = 0}, "mesecons:test_conductor_off")
world.set_node(layout[1][1], "mesecons:test_receptor_on")
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_multiconductor_101", world.get_node(layout[4][1]).name)
end)
end)

View File

@ -1,5 +1,7 @@
-- The BLINKY_PLANT
local S = minetest.get_translator(minetest.get_current_modname())
local toggle_timer = function (pos)
local timer = minetest.get_node_timer(pos)
if timer:is_started() then
@ -20,7 +22,7 @@ local on_timer = function (pos)
end
mesecon.register_node("mesecons_blinkyplant:blinky_plant", {
description="Blinky Plant",
description= S("Blinky Plant"),
drawtype = "plantlike",
inventory_image = "jeija_blinky_plant_off.png",
paramtype = "light",

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_blinkyplant
### init.lua ###
Blinky Plant=Palpebruma Planto

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_blinkyplant
### init.lua ###
Blinky Plant=

View File

@ -1,6 +1,7 @@
-- WALL BUTTON
-- A button that when pressed emits power for 1 second
-- and then turns off again
local S = minetest.get_translator(minetest.get_current_modname())
mesecon.button_turnoff = function (pos)
local node = minetest.get_node(pos)
@ -45,7 +46,7 @@ minetest.register_node("mesecons_button:button_off", {
}
},
groups = {dig_immediate=2, mesecon_needs_receiver = 1},
description = "Button",
description = S("Button"),
on_rightclick = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
@ -92,7 +93,7 @@ minetest.register_node("mesecons_button:button_on", {
},
groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon_needs_receiver = 1},
drop = 'mesecons_button:button_off',
description = "Button",
description = S("Button"),
sounds = mesecon.node_sound.stone,
mesecons = {receptor = {
state = mesecon.state.on,

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_button
### init.lua ###
Button=Butono

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_button
### init.lua ###
Button=

View File

@ -1,6 +1,8 @@
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_chatcommand("say", {
params = "<text>",
description = "Say <text> as the server",
description = S("Say <text> as the server"),
privs = {server=true},
func = function(name, param)
minetest.chat_send_all(name .. ": " .. param)
@ -9,7 +11,7 @@ minetest.register_chatcommand("say", {
minetest.register_chatcommand("tell", {
params = "<name> <text>",
description = "Say <text> to <name> privately",
description = S("Say <text> to <name> privately"),
privs = {shout=true},
func = function(name, param)
local found, _, target, message = param:find("^([^%s]+)%s+(.*)$")
@ -26,7 +28,7 @@ minetest.register_chatcommand("tell", {
minetest.register_chatcommand("hp", {
params = "<name> <value>",
description = "Set health of <name> to <value> hitpoints",
description = S("Set health of <name> to <value> hitpoints"),
privs = {ban=true},
func = function(name, param)
local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$")
@ -180,7 +182,7 @@ local function can_dig(pos, player)
end
minetest.register_node("mesecons_commandblock:commandblock_off", {
description = "Command Block",
description = S("Command Block"),
tiles = {"jeija_commandblock_off.png"},
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
is_ground_content = false,

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_commandblock
### init.lua ###
Say <text> as the server=Diru <teksto> kiel la servilo
Say <text> to <name> privately=Diru <teksto> al <nomo> private
Set health of <name> to <value> hitpoints=Agordu sanon de <nomo> al <valoro>
Command Block=Komando-Bloko

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_commandblock
### init.lua ###
Say <text> as the server=
Say <text> to <name> privately=
Set health of <name> to <value> hitpoints=
Command Block=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- Function that get the input/output rules of the delayer
local delayer_get_output_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}})
@ -69,7 +71,7 @@ if i > 1 then
end
local off_state = {
description = "Delayer",
description = S("Delayer"),
tiles = {
"mesecons_delayer_off_"..tostring(i)..".png",
"mesecons_delayer_bottom.png",
@ -112,7 +114,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state)
-- Activated delayer definition defaults
local on_state = {
description = "You hacker you",
description = S("You hacker you"),
tiles = {
"mesecons_delayer_on_"..tostring(i)..".png",
"mesecons_delayer_bottom.png",

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_delayer
### init.lua ###
Delayer=Prokrasto
You hacker you=Vi hakisto

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_delayer
### init.lua ###
Delayer=
You hacker you=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local side_texture = mesecon.texture.steel_block or "mesecons_detector_side.png"
local GET_COMMAND = "GET"
@ -71,7 +73,7 @@ minetest.register_node("mesecons_detector:object_detector_off", {
is_ground_content = false,
walkable = true,
groups = {cracky=3},
description="Player Detector",
description= S("Player Detector"),
mesecons = {receptor = {
state = mesecon.state.off,
rules = mesecon.rules.pplate
@ -247,7 +249,7 @@ minetest.register_node("mesecons_detector:node_detector_off", {
is_ground_content = false,
walkable = true,
groups = {cracky=3},
description="Node Detector",
description = S("Node Detector"),
mesecons = {receptor = {
state = mesecon.state.off
}},

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_detector
### init.lua ###
Player Detector=Ludanta Detektilo
Node Detector=Noda Detektilo

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_detector
### init.lua ###
Player Detector=
Node Detector=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local corner_selectionbox = {
type = "fixed",
fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 },
@ -36,7 +38,7 @@ minetest.register_node("mesecons_extrawires:corner_on", {
minetest.register_node("mesecons_extrawires:corner_off", {
drawtype = "mesh",
description = "Insulated Mesecon Corner",
description = S("Insulated Mesecon Corner"),
mesh = "mesecons_extrawires_corner.obj",
tiles = {
{ name = "jeija_insulated_wire_sides_off.png", backface_culling = true },
@ -67,3 +69,9 @@ minetest.register_craft({
{"", "mesecons_insulated:insulated_off"},
}
})
minetest.register_craft({
output = "mesecons_insulated:insulated_off",
type = "shapeless",
recipe = {"mesecons_extrawires:corner_off"}
})

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local crossover_rules = {
{--first wire
{x=-1,y=0,z=0},
@ -17,7 +19,7 @@ local crossover_states = {
}
minetest.register_node("mesecons_extrawires:crossover_off", {
description = "Insulated Mesecon Crossover",
description = S("Insulated Mesecon Crossover"),
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = {
@ -43,7 +45,7 @@ minetest.register_node("mesecons_extrawires:crossover_off", {
})
minetest.register_node("mesecons_extrawires:crossover_01", {
description = "You hacker you!",
description = S("You hacker you!"),
drop = "mesecons_extrawires:crossover_off",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
@ -70,7 +72,7 @@ minetest.register_node("mesecons_extrawires:crossover_01", {
})
minetest.register_node("mesecons_extrawires:crossover_10", {
description = "You hacker you!",
description = S("You hacker you!"),
drop = "mesecons_extrawires:crossover_off",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
@ -97,7 +99,7 @@ minetest.register_node("mesecons_extrawires:crossover_10", {
})
minetest.register_node("mesecons_extrawires:crossover_on", {
description = "You hacker you!",
description = S("You hacker you!"),
drop = "mesecons_extrawires:crossover_off",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local doublecorner_selectionbox = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
@ -31,7 +33,7 @@ for k, state in ipairs(doublecorner_states) do
minetest.register_node(state, {
drawtype = "mesh",
mesh = "mesecons_extrawires_doublecorner.obj",
description = "Insulated Mesecon Double Corner",
description = S("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 },

View File

@ -0,0 +1,20 @@
# textdomain: mesecons_extrawires
### corner.lua ###
Insulated Mesecon Corner=Izolita Mesekonduktila Angulo
### crossover.lua ###
Insulated Mesecon Crossover=Izolita Mesekonduktila Interkruciĝo
You hacker you!=Vi hakisto
### doublecorner.lua ###
Insulated Mesecon Double Corner=Izolita Mesekonduktila Duobla Angulo
### mesewire.lua ###
Mese Wire=Mesea Drato
### tjunction.lua ###
Insulated Mesecon T-junction=Izolita Mesekonduktila T-Kruciĝo
### vertical.lua ###
Vertical Mesecon=Vertikala Mesekonduktilo

View File

@ -0,0 +1,20 @@
# textdomain: mesecons_extrawires
### corner.lua ###
Insulated Mesecon Corner=
### crossover.lua ###
Insulated Mesecon Crossover=
You hacker you!=
### doublecorner.lua ###
Insulated Mesecon Double Corner=
### mesewire.lua ###
Mese Wire=
### tjunction.lua ###
Insulated Mesecon T-junction=
### vertical.lua ###
Vertical Mesecon=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local mese_nodename = minetest.registered_aliases["mesecons_gamecompat:mese"]
if mese_nodename then
-- Convert placeholders.
@ -6,7 +8,7 @@ else
-- Register placeholder.
mese_nodename = "mesecons_extrawires:mese"
minetest.register_node("mesecons_extrawires:mese", {
description = "Mese Wire",
description = S("Mese Wire"),
tiles = {"mesecons_wire_off.png"},
paramtype = "light",
light_source = 3,

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local tjunction_nodebox = {
type = "fixed",
-- ±0.001 is to prevent z-fighting
@ -48,7 +50,7 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
minetest.register_node("mesecons_extrawires:tjunction_off", {
drawtype = "nodebox",
description = "Insulated Mesecon T-junction",
description = S("Insulated Mesecon T-junction"),
tiles = {
"jeija_insulated_wire_tjunction_tb_off.png",
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180",

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local vertical_box = {
type = "fixed",
fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16}
@ -77,7 +79,7 @@ end
-- Vertical wire
mesecon.register_node("mesecons_extrawires:vertical", {
description = "Vertical Mesecon",
description = S("Vertical Mesecon"),
drawtype = "nodebox",
walkable = false,
paramtype = "light",
@ -110,7 +112,7 @@ mesecon.register_node("mesecons_extrawires:vertical", {
-- Vertical wire top
mesecon.register_node("mesecons_extrawires:vertical_top", {
description = "Vertical mesecon",
description = S("Vertical Mesecon"),
drawtype = "nodebox",
walkable = false,
paramtype = "light",
@ -142,7 +144,7 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
-- Vertical wire bottom
mesecon.register_node("mesecons_extrawires:vertical_bottom", {
description = "Vertical mesecon",
description = S("Vertical Mesecon"),
drawtype = "nodebox",
walkable = false,
paramtype = "light",

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local plg = {}
plg.rules = {}
-- per-player formspec positions
@ -59,7 +61,7 @@ plg.register_nodes = function(template)
end
plg.register_nodes({
description = "FPGA",
description = S("FPGA"),
drawtype = "nodebox",
tiles = {
"", -- replaced later

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_fpga
### init.lua ###
FPGA=FPGA
### tool.lua ###
FPGA Programmer=FPGA Programilo

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_fpga
### init.lua ###
FPGA=
### tool.lua ###
FPGA Programmer=

View File

@ -0,0 +1,106 @@
require("mineunit")
fixture("mesecons_fpga")
fixture("screwdriver")
local pos = {x = 0, y = 0, z = 0}
local pos_a = {x = -1, y = 0, z = 0}
local pos_b = {x = 0, y = 0, z = 1}
local pos_c = {x = 1, y = 0, z = 0}
local pos_d = {x = 0, y = 0, z = -1}
describe("FPGA rotation", function()
before_each(function()
world.set_node(pos, "mesecons_fpga:fpga0000")
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("rotates I/O operands clockwise", function()
mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}})
local node = world.get_node(pos)
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_FACE)
mesecon._test_place(pos_b, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
mesecon._test_dig(pos_b)
mesecon._test_place(pos_c, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
end)
it("rotates I/O operands counterclockwise", function()
mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}})
local node = world.get_node(pos)
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS)
mesecon._test_place(pos_d, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
mesecon._test_dig(pos_d)
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
end)
it("updates ports", function()
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
local node = world.get_node(pos)
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS)
assert.equal("mesecons_fpga:fpga0001", world.get_node(pos).name)
end)
end)
describe("FPGA programmer", function()
local pos2 = {x = 10, y = 0, z = 0}
before_each(function()
world.set_node(pos, "mesecons_fpga:fpga0000")
world.set_node(pos2, "mesecons_fpga:fpga0000")
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("transfers instructions", function()
mesecon._test_program_fpga(pos2, {{"NOT", "A", "B"}})
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
end)
it("does not copy from new FPGAs", function()
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
end)
it("does not copy from cleared FPGAs", function()
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
mesecon._test_program_fpga(pos2, {{"=", "A", "B"}})
mesecon._test_program_fpga(pos2, {})
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
end)
it("does not copy from non-FPGA nodes", function()
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(vector.add(pos2, 1)))
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
end)
end)

View File

@ -0,0 +1,235 @@
require("mineunit")
fixture("mesecons_fpga")
describe("FPGA logic", function()
local pos = {x = 0, y = 0, z = 0}
local pos_a = {x = -1, y = 0, z = 0}
local pos_b = {x = 0, y = 0, z = 1}
local pos_c = {x = 1, y = 0, z = 0}
local pos_d = {x = 0, y = 0, z = -1}
local fpga_set = false
local function set_fpga()
if not fpga_set then
world.set_node(pos, "mesecons_fpga:fpga0000")
fpga_set = true
end
end
before_each(set_fpga)
local function reset_world()
if fpga_set then
mesecon._test_reset()
world.clear()
fpga_set = false
end
end
after_each(reset_world)
local function test_program(inputs, outputs, program)
set_fpga()
mesecon._test_program_fpga(pos, program)
if inputs.a then mesecon._test_place(pos_a, "mesecons:test_receptor_on") end
if inputs.b then mesecon._test_place(pos_b, "mesecons:test_receptor_on") end
if inputs.c then mesecon._test_place(pos_c, "mesecons:test_receptor_on") end
if inputs.d then mesecon._test_place(pos_d, "mesecons:test_receptor_on") end
mineunit:execute_globalstep() -- Execute receptor_on actions
mineunit:execute_globalstep() -- Execute activate/change actions
local expected_name = "mesecons_fpga:fpga"
.. (outputs.d and 1 or 0) .. (outputs.c and 1 or 0)
.. (outputs.b and 1 or 0) .. (outputs.a and 1 or 0)
assert.equal(expected_name, world.get_node(pos).name)
reset_world()
end
it("operator and", function()
local prog = {{"A", "AND", "B", "C"}}
test_program({}, {}, prog)
test_program({a = true}, {}, prog)
test_program({b = true}, {}, prog)
test_program({a = true, b = true}, {c = true}, prog)
end)
it("operator or", function()
local prog = {{"A", "OR", "B", "C"}}
test_program({}, {}, prog)
test_program({a = true}, {c = true}, prog)
test_program({b = true}, {c = true}, prog)
test_program({a = true, b = true}, {c = true}, prog)
end)
it("operator not", function()
local prog = {{"NOT", "A", "B"}}
test_program({}, {b = true}, prog)
test_program({a = true}, {}, prog)
end)
it("operator xor", function()
local prog = {{"A", "XOR", "B", "C"}}
test_program({}, {}, prog)
test_program({a = true}, {c = true}, prog)
test_program({b = true}, {c = true}, prog)
test_program({a = true, b = true}, {}, prog)
end)
it("operator nand", function()
local prog = {{"A", "NAND", "B", "C"}}
test_program({}, {c = true}, prog)
test_program({a = true}, {c = true}, prog)
test_program({b = true}, {c = true}, prog)
test_program({a = true, b = true}, {}, prog)
end)
it("operator buf", function()
local prog = {{"=", "A", "B"}}
test_program({}, {}, prog)
test_program({a = true}, {b = true}, prog)
end)
it("operator xnor", function()
local prog = {{"A", "XNOR", "B", "C"}}
test_program({}, {c = true}, prog)
test_program({a = true}, {}, prog)
test_program({b = true}, {}, prog)
test_program({a = true, b = true}, {c = true}, prog)
end)
it("operator nor", function()
local prog = {{"A", "NOR", "B", "C"}}
test_program({}, {c = true}, prog)
test_program({a = true}, {}, prog)
test_program({b = true}, {}, prog)
test_program({a = true, b = true}, {}, prog)
end)
it("rejects duplicate operands", function()
test_program({a = true}, {}, {{"A", "OR", "A", "B"}})
test_program({a = true}, {}, {{"=", "A", "0"}, {"0", "OR", "0", "B"}})
end)
it("rejects unassigned memory operands", function()
test_program({a = true}, {}, {{"A", "OR", "0", "B"}})
test_program({a = true}, {}, {{"0", "OR", "A", "B"}})
end)
it("rejects double memory assignment", function()
test_program({a = true}, {}, {{"=", "A", "0"}, {"=", "A", "0"}, {"=", "0", "B"}})
end)
it("rejects assignment to memory operand", function()
test_program({a = true}, {}, {{"=", "A", "0"}, {"A", "OR", "0", "0"}, {"=", "0", "B"}})
end)
it("allows double port assignment", function()
test_program({a = true}, {b = true}, {{"NOT", "A", "B"}, {"=", "A", "B"}})
end)
it("allows assignment to port operand", function()
test_program({a = true}, {b = true}, {{"A", "OR", "B", "B"}})
end)
it("preserves initial pin states", function()
test_program({a = true}, {b = true}, {{"=", "A", "B"}, {"=", "B", "C"}})
end)
it("rejects binary operations with single operands", function()
test_program({a = true}, {}, {{"=", "A", "B"}, {" ", "OR", "A", "C"}})
test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "OR", " ", "C"}})
end)
it("rejects unary operations with first operands", function()
test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "=", " ", "C"}})
end)
it("rejects operations without destinations", function()
test_program({a = true}, {}, {{"=", "A", "B"}, {"=", "A", " "}})
end)
it("allows blank statements", function()
test_program({a = true}, {b = true, c = true}, {
{" ", " ", " ", " "},
{"=", "A", "B"},
{" ", " ", " ", " "},
{" ", " ", " ", " "},
{"=", "A", "C"},
})
end)
it("transmits output signals to adjacent nodes", function()
mesecon._test_program_fpga(pos, {
{"=", "A", "B"},
{"=", "A", "C"},
{"NOT", "A", "D"},
})
mesecon._test_place(pos_b, "mesecons:test_effector")
mesecon._test_place(pos_c, "mesecons:test_effector")
mesecon._test_place(pos_d, "mesecons:test_effector")
mineunit:execute_globalstep() -- Execute receptor_on actions
mineunit:execute_globalstep() -- Execute activate/change actions
-- Makes an object from the last three effector events in the list for use with assert.same.
-- This is necessary to ignore the ordering of events.
local function event_tester(list)
local o = {list[#list - 2], list[#list - 1], list[#list - 0]}
table.sort(o, function(a, b)
local fmt = "%s %d %d %d"
return fmt:format(a[1], a[2].x, a[2].y, a[2].z) < fmt:format(b[1], b[2].x, b[2].y, b[2].z)
end)
return o
end
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal("mesecons_fpga:fpga0110", world.get_node(pos).name)
assert.same(event_tester({{"on", pos_b}, {"on", pos_c}, {"off", pos_d}}), event_tester(mesecon._test_effector_events))
mesecon._test_dig(pos_a)
mineunit:execute_globalstep() -- Execute receptor_off action
mineunit:execute_globalstep() -- Execute deactivate/change actions
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
assert.same(event_tester({{"off", pos_b}, {"off", pos_c}, {"on", pos_d}}), event_tester(mesecon._test_effector_events))
end)
it("considers past outputs in determining inputs", function()
-- Memory cell: Turning on A turns on C; turning on B turns off C.
mesecon._test_program_fpga(pos, {
{"A", "OR", "C", "0"},
{"B", "OR", "D", "1"},
{"NOT", "A", "2"},
{"NOT", "B", "3"},
{"0", "AND", "3", "C"},
{"1", "AND", "2", "D"},
})
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on actions
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name)
mesecon._test_dig(pos_a)
mineunit:execute_globalstep() -- Execute receptor_off actions
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name)
mesecon._test_place(pos_b, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on actions
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
mesecon._test_dig(pos_b)
mineunit:execute_globalstep() -- Execute receptor_off actions
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
end)
end)

View File

@ -0,0 +1 @@
fixture_paths = {"../.test_fixtures"}

View File

@ -1,8 +1,10 @@
local S = minetest.get_translator(minetest.get_current_modname())
return function(plg)
minetest.register_tool("mesecons_fpga:programmer", {
description = "FPGA Programmer",
description = S("FPGA Programmer"),
inventory_image = "jeija_fpga_programmer.png",
stack_max = 1,
on_place = function(itemstack, placer, pointed_thing)
@ -21,7 +23,7 @@ minetest.register_tool("mesecons_fpga:programmer", {
minetest.sound_play("mesecons_fpga_fail", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true)
return itemstack
end
itemstack:set_metadata(meta:get_string("instr"))
itemstack:get_meta():set_string("", meta:get_string("instr"))
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)
@ -42,7 +44,7 @@ minetest.register_tool("mesecons_fpga:programmer", {
return itemstack
end
local imeta = itemstack:get_metadata()
local imeta = itemstack:get_meta():get_string("")
if imeta == "" then
minetest.chat_send_player(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)

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- HYDRO_TURBINE
-- Water turbine:
-- Active if flowing >water< above it
@ -17,7 +19,7 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", {
is_ground_content = false,
wield_scale = {x=0.75, y=0.75, z=0.75},
groups = {dig_immediate=2},
description="Water Turbine",
description = S("Water Turbine"),
paramtype = "light",
selection_box = {
type = "fixed",
@ -47,7 +49,7 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", {
inventory_image = "jeija_hydro_turbine_inv.png",
drop = "mesecons_hydroturbine:hydro_turbine_off 1",
groups = {dig_immediate=2,not_in_creative_inventory=1},
description="Water Turbine",
description = S("Water Turbine"),
paramtype = "light",
selection_box = {
type = "fixed",
@ -97,9 +99,8 @@ nodenames = {"mesecons_hydroturbine:hydro_turbine_on"},
minetest.register_craft({
output = "mesecons_hydroturbine:hydro_turbine_off 2",
recipe = {
{"","grup:stick", ""},
{"","group:stick", ""},
{"group:stick", "mesecons_gamecompat:steel_ingot", "group:stick"},
{"","group:stick", ""},
}
})

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_hydroturbine
### init.lua ###
Water Turbine=Akva Turbino

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_hydroturbine
### init.lua ###
Water Turbine=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local insulated_wire_get_rules = mesecon.horiz_rules_getter({
{x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0},
@ -5,7 +7,7 @@ local insulated_wire_get_rules = mesecon.horiz_rules_getter({
minetest.register_node("mesecons_insulated:insulated_on", {
drawtype = "nodebox",
description = "Straight Insulated Mesecon",
description = S("Straight Insulated Mesecon"),
tiles = {
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_sides_on.png",
@ -42,7 +44,7 @@ minetest.register_node("mesecons_insulated:insulated_on", {
minetest.register_node("mesecons_insulated:insulated_off", {
drawtype = "nodebox",
description = "Straight Insulated Mesecon",
description = S("Straight Insulated Mesecon"),
tiles = {
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_sides_off.png",

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_insulated
### init.lua ###
Straight Insulated Mesecon=Rekta Izolita Mesekonduktilo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_insulated
### init.lua ###
Straight Insulated Mesecon=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- MESELAMPS
-- A lamp is "is an electrical device used to create artificial light" (wikipedia)
-- guess what?
@ -50,7 +52,7 @@ minetest.register_node("mesecons_lamp:lamp_off", {
node_box = mesecon_lamp_box,
selection_box = mesecon_lamp_box,
groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1},
description = "Mesecon Lamp",
description = S("Mesecon Lamp"),
sounds = mesecon.node_sound.glass,
mesecons = {effector = {
action_on = function (pos, node)

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_lamp
### init.lua ###
Mesecon Lamp=Mesekonduktila Lampo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_lamp
### init.lua ###
Mesecon Lamp=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local lightstone_rules = {
{x=0, y=0, z=-1},
{x=1, y=0, z=0},
@ -59,15 +61,15 @@ function mesecon.lightstone_add(name, base_item, texture_off, texture_on, desc)
end
mesecon.lightstone_add("red", "mesecons_gamecompat:dye_red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", "Red Lightstone")
mesecon.lightstone_add("green", "mesecons_gamecompat:dye_green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", "Green Lightstone")
mesecon.lightstone_add("blue", "mesecons_gamecompat:dye_blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", "Blue Lightstone")
mesecon.lightstone_add("gray", "mesecons_gamecompat:dye_grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", "Grey Lightstone")
mesecon.lightstone_add("darkgray", "mesecons_gamecompat:dye_dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", "Dark Grey Lightstone")
mesecon.lightstone_add("yellow", "mesecons_gamecompat:dye_yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", "Yellow Lightstone")
mesecon.lightstone_add("orange", "mesecons_gamecompat:dye_orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", "Orange Lightstone")
mesecon.lightstone_add("white", "mesecons_gamecompat:dye_white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", "White Lightstone")
mesecon.lightstone_add("pink", "mesecons_gamecompat:dye_pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", "Pink Lightstone")
mesecon.lightstone_add("magenta", "mesecons_gamecompat:dye_magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", "Magenta Lightstone")
mesecon.lightstone_add("cyan", "mesecons_gamecompat:dye_cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", "Cyan Lightstone")
mesecon.lightstone_add("violet", "mesecons_gamecompat:dye_violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", "Violet Lightstone")
mesecon.lightstone_add("red", "mesecons_gamecompat:dye_red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", S("Red Lightstone"))
mesecon.lightstone_add("green", "mesecons_gamecompat:dye_green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", S("Green Lightstone"))
mesecon.lightstone_add("blue", "mesecons_gamecompat:dye_blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", S("Blue Lightstone"))
mesecon.lightstone_add("gray", "mesecons_gamecompat:dye_grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", S("Grey Lightstone"))
mesecon.lightstone_add("darkgray", "mesecons_gamecompat:dye_dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", S("Dark Grey Lightstone"))
mesecon.lightstone_add("yellow", "mesecons_gamecompat:dye_yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", S("Yellow Lightstone"))
mesecon.lightstone_add("orange", "mesecons_gamecompat:dye_orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", S("Orange Lightstone"))
mesecon.lightstone_add("white", "mesecons_gamecompat:dye_white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", S("White Lightstone"))
mesecon.lightstone_add("pink", "mesecons_gamecompat:dye_pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", S("Pink Lightstone"))
mesecon.lightstone_add("magenta", "mesecons_gamecompat:dye_magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", S("Magenta Lightstone"))
mesecon.lightstone_add("cyan", "mesecons_gamecompat:dye_cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", S("Cyan Lightstone"))
mesecon.lightstone_add("violet", "mesecons_gamecompat:dye_violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", S("Violet Lightstone"))

View File

@ -0,0 +1,15 @@
# textdomain: mesecons_lightstone
### init.lua ###
Red Lightstone=Ruĝa Lumŝtono
Green Lightstone=Verda Lumŝtono
Blue Lightstone=Blua Lumŝtono
Grey Lightstone=Griza Lumŝtono
Dark Grey Lightstone=Malhela Griza Lumŝtono
Yellow Lightstone=Flava Lumŝtono
Orange Lightstone=Oranĝa Lumŝtono
White Lightstone=Blanka Lumŝtono
Pink Lightstone=Rozkolora Lumŝtono
Magenta Lightstone=Magenta Lumŝtono
Cyan Lightstone=Cejana Lumŝtono
Violet Lightstone=Viola Lumŝtono

View File

@ -0,0 +1,15 @@
# textdomain: mesecons_lightstone
### init.lua ###
Red Lightstone=
Green Lightstone=
Blue Lightstone=
Grey Lightstone=
Dark Grey Lightstone=
Yellow Lightstone=
Orange Lightstone=
White Lightstone=
Pink Lightstone=
Magenta Lightstone=
Cyan Lightstone=
Violet Lightstone=

View File

@ -28,6 +28,8 @@
-- (see where local env is defined)
-- Something nice to play is is appending minetest.env to it.
local S = minetest.get_translator(minetest.get_current_modname())
local BASENAME = "mesecons_luacontroller:luacontroller"
local rules = {
@ -201,11 +203,13 @@ end
-------------------------
local function safe_print(param)
local string_meta = getmetatable("")
local sandbox = string_meta.__index
string_meta.__index = string -- Leave string sandbox temporarily
print(dump(param))
string_meta.__index = sandbox -- Restore string sandbox
if mesecon.setting("luacontroller_print_behavior", "log") == "log" then
local string_meta = getmetatable("")
local sandbox = string_meta.__index
string_meta.__index = string -- Leave string sandbox temporarily
minetest.log("action", string.format("[mesecons_luacontroller] print(%s)", dump(param)))
string_meta.__index = sandbox -- Restore string sandbox
end
end
local function safe_date()
@ -851,7 +855,7 @@ for d = 0, 1 do
}
minetest.register_node(node_name, {
description = "Luacontroller",
description = S("Luacontroller"),
drawtype = "nodebox",
tiles = {
top,

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_luacontroller
### init.lua ###
Luacontroller=Luaregilo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_luacontroller
### init.lua ###
Luacontroller=

View File

@ -0,0 +1,38 @@
require("mineunit")
-- This test is done in a separate file since it requires different configuration at startup.
mineunit("core")
minetest.settings:set("mesecon.luacontroller_lightweight_interrupts", "true")
fixture("mesecons_luacontroller")
describe("LuaController lightweight interrupt", function()
local pos = {x = 0, y = 0, z = 0}
before_each(function()
mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000")
mineunit:execute_globalstep() -- Execute receptor_on action
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("works", function()
mesecon._test_program_luac(pos, [[
if event.type == "program" then
interrupt(5)
interrupt(10)
elseif event.type == "interrupt" then
port.a = not pin.a
end
]])
mineunit:execute_globalstep(0.1)
mineunit:execute_globalstep(9)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
mineunit:execute_globalstep(1)
mineunit:execute_globalstep(0.1)
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
end)
end)

View File

@ -0,0 +1,176 @@
require("mineunit")
fixture("mesecons_luacontroller")
-- Digiline is not tested, since that would require the digiline mod.
describe("LuaController", function()
local pos = {x = 0, y = 0, z = 0}
local pos_a = {x = -1, y = 0, z = 0}
before_each(function()
mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000")
mineunit:execute_globalstep() -- Execute receptor_on action
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("rejects binary code", function()
local ok = mesecon._test_program_luac(pos, string.dump(function() end))
assert.is_false(ok)
end)
it("I/O", function()
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
mesecon._test_program_luac(pos, [[
port.a = not pin.a
port.b = not pin.b
port.c = not pin.c
port.d = not pin.d
]])
assert.equal("mesecons_luacontroller:luacontroller1110", world.get_node(pos).name)
mesecon._test_dig(pos_a)
mineunit:execute_globalstep() -- Execute receptor_off action
mineunit:execute_globalstep() -- Execute deactivate/change actions
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
end)
it("memory", function()
mesecon._test_program_luac(pos, [[
if not mem.x then
mem.x = {}
mem.x[mem.x] = {true, "", 1.2}
else
local b, s, n = unpack(mem.x[mem.x])
if b == true and s == "" and n == 1.2 then
port.d = true
end
end
]])
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
assert.equal("mesecons_luacontroller:luacontroller1000", world.get_node(pos).name)
end)
it("interrupts without IDs", function()
mesecon._test_program_luac(pos, [[
if event.type == "program" then
interrupt(4)
interrupt(8)
elseif event.type == "interrupt" then
port.a = not pin.a
end
]])
mineunit:execute_globalstep(0.1)
mineunit:execute_globalstep(3)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
mineunit:execute_globalstep(1)
mineunit:execute_globalstep(0.1)
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mineunit:execute_globalstep(3)
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mineunit:execute_globalstep(1)
mineunit:execute_globalstep(0.1)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
it("interrupts with IDs", function()
mesecon._test_program_luac(pos, [[
if event.type == "program" then
interrupt(2, "a")
interrupt(4, "a")
interrupt(16, "b")
elseif event.type == "interrupt" then
if event.iid == "a" then
interrupt(5, "b")
interrupt(4, "b")
end
port.a = not pin.a
end
]])
mineunit:execute_globalstep(0.1)
mineunit:execute_globalstep(3)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
mineunit:execute_globalstep(1)
mineunit:execute_globalstep(0.1)
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mineunit:execute_globalstep(3)
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mineunit:execute_globalstep(1)
mineunit:execute_globalstep(0.1)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
it("limits interrupt ID size", function()
mesecon._test_program_luac(pos, [[
if event.type == "program" then
interrupt(0, (" "):rep(257))
elseif event.type == "interrupt" then
port.a = not pin.a
end
]])
mineunit:execute_globalstep(3)
mineunit:execute_globalstep(3)
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
it("string.rep", function()
mesecon._test_program_luac(pos, [[
(" "):rep(64000)
port.a = true
]])
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mesecon._test_program_luac(pos, [[
(" "):rep(64001)
port.b = true
]])
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
it("string.find", function()
mesecon._test_program_luac(pos, [[
port.a = (" a"):find("a", nil, true) == 2
]])
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
mesecon._test_program_luac(pos, [[
(" a"):find("a", nil)
port.b = true
]])
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
it("overheats", function()
mesecon._test_program_luac(pos, [[
interrupt(0)
interrupt(0)
]])
mineunit:execute_globalstep() -- Execute 2 interrupts
mineunit:execute_globalstep() -- Execute 4 interrupts
mineunit:execute_globalstep() -- Execute 8 interrupts
mineunit:execute_globalstep() -- Execute 16 interrupts
assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name)
end)
it("limits memory", function()
mesecon._test_program_luac(pos, [[
port.a = true
mem.x = (" "):rep(50000) .. (" "):rep(50000)
]])
assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name)
end)
it("limits run time", function()
mesecon._test_program_luac(pos, [[
port.a = true
for i = 1, 1000000 do end
]])
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
end)
end)

View File

@ -0,0 +1 @@
fixture_paths = {"../.test_fixtures"}

View File

@ -1,14 +1,16 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- Glue and fiber
minetest.register_craftitem("mesecons_materials:glue", {
image = "mesecons_glue.png",
on_place_on_ground = minetest.craftitem_place_item,
description="Glue",
description = S("Glue"),
})
minetest.register_craftitem("mesecons_materials:fiber", {
image = "mesecons_fiber.png",
on_place_on_ground = minetest.craftitem_place_item,
description="Fiber",
description = S("Fiber"),
})
minetest.register_craft({
@ -29,7 +31,7 @@ minetest.register_craft({
minetest.register_craftitem("mesecons_materials:silicon", {
image = "mesecons_silicon.png",
on_place_on_ground = minetest.craftitem_place_item,
description="Silicon",
description = S("Silicon"),
})
minetest.register_craft({

View File

@ -0,0 +1,6 @@
# textdomain: mesecons_materials
### init.lua ###
Glue=Gluo
Fiber=Fibro
Silicon=Silicio

View File

@ -0,0 +1,6 @@
# textdomain: mesecons_materials
### init.lua ###
Glue=
Fiber=
Silicon=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local EEPROM_SIZE = 255
local microc_rules = {}
@ -57,7 +59,7 @@ if nodename ~= "mesecons_microcontroller:microcontroller0000" then
end
minetest.register_node(nodename, {
description = "Microcontroller",
description = S("Microcontroller"),
drawtype = "nodebox",
tiles = {
top,

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_microcontroller
### init.lua ###
Microcontroller=Mikroregilo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_microcontroller
### init.lua ###
Microcontroller=

View File

@ -8,6 +8,8 @@
-- Pushes all block in front of it
-- Pull all blocks in its back
local S = minetest.get_translator(minetest.get_current_modname())
-- settings:
local timer_interval = 1 / mesecon.setting("movestone_speed", 3)
local max_push = mesecon.setting("movestone_max_push", 50)
@ -128,7 +130,7 @@ mesecon.register_movestone("mesecons_movestones:movestone", {
"jeija_movestone_arrows.png",
},
groups = {cracky = 3},
description = "Movestone",
description = S("Movestone"),
sounds = mesecon.node_sound.stone
}, false, false)
@ -142,7 +144,7 @@ mesecon.register_movestone("mesecons_movestones:sticky_movestone", {
"jeija_sticky_movestone.png",
},
groups = {cracky = 3},
description = "Sticky Movestone",
description = S("Sticky Movestone"),
sounds = mesecon.node_sound.stone,
}, true, false)
@ -156,7 +158,7 @@ mesecon.register_movestone("mesecons_movestones:movestone_vertical", {
"jeija_movestone_arrows.png^[transformR90",
},
groups = {cracky = 3},
description = "Vertical Movestone",
description = S("Vertical Movestone"),
sounds = mesecon.node_sound.stone
}, false, true)
@ -170,7 +172,7 @@ mesecon.register_movestone("mesecons_movestones:sticky_movestone_vertical", {
"jeija_movestone_arrows.png^[transformR90",
},
groups = {cracky = 3},
description = "Vertical Sticky Movestone",
description = S("Vertical Sticky Movestone"),
sounds = mesecon.node_sound.stone,
}, true, true)

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_movestones
### init.lua ###
Movestone=Movŝtono
Sticky Movestone=Glueca Movŝtono
Vertical Movestone=Vertikala Movŝtono
Vertical Sticky Movestone=Vertikala Glueca Movŝtono

View File

@ -0,0 +1,7 @@
# textdomain: mesecons_movestones
### init.lua ###
Movestone=
Sticky Movestone=
Vertical Movestone=
Vertical Sticky Movestone=

View File

@ -0,0 +1 @@
fixture_paths = {"../.test_fixtures"}

View File

@ -0,0 +1,297 @@
require("mineunit")
fixture("mesecons_mvps")
world.set_default_node("air")
describe("node movement", function()
after_each(function()
mesecon._test_reset()
world.clear()
end)
it("works with no moved nodes", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
assert.same({true, {}, {}}, {mesecon.mvps_push(pos, dir, 1, "")})
assert.same({true, {}, {}}, {mesecon.mvps_pull_all(pos, dir, 1, "")})
assert.same({true, {}, {}}, {mesecon.mvps_pull_single(pos, dir, 1, "")})
end)
it("works with simple stack", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off")
assert.is_true((mesecon.mvps_push(pos, dir, 2, "")))
assert.equal("air", world.get_node(pos).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name)
assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 2, "")))
assert.equal("mesecons:test_conductor_off", world.get_node(pos).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
assert.equal("air", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name)
assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 1, "")))
assert.equal("mesecons:test_conductor_off", world.get_node(vector.subtract(pos, dir)).name)
assert.equal("air", world.get_node(pos).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
end)
it("works with sticky nodes", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 0, y = 1, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
world.set_node(vector.offset(pos, 0, 1, 0), "mesecons_mvps:test_sticky")
world.set_node(vector.offset(pos, 1, 1, 0), "mesecons:test_conductor_off")
world.set_node(vector.offset(pos, 1, 2, 0), "mesecons:test_conductor_off")
assert.is_true((mesecon.mvps_push(pos, dir, 4, "")))
assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 3, 0)).name)
assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 4, "")))
assert.equal("air", world.get_node(vector.offset(pos, 1, 0, 0)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 1, 0)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name)
assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 3, "")))
assert.equal("air", world.get_node(vector.offset(pos, 1, -1, 0)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 0, 0)).name)
assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name)
end)
it("respects maximum", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off")
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
end)
it("is blocked by basic stopper", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons_mvps:test_stopper")
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
end)
it("is blocked by conditional stopper", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 0})
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 1})
assert.is_true((mesecon.mvps_push(pos, dir, 1, "")))
end)
-- TODO: I think this is supposed to work?
pending("is blocked by ignore", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
world.set_node(vector.add(pos, dir), "ignore")
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
end)
it("moves metadata", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
minetest.get_meta(pos):set_string("foo", "bar")
minetest.get_node_timer(pos):set(12, 34)
mesecon.mvps_push(pos, dir, 1, "")
assert.equal("bar", minetest.get_meta(vector.add(pos, dir)):get("foo"))
local moved_timer = minetest.get_node_timer(vector.add(pos, dir))
assert.equal(12, moved_timer:get_timeout())
assert.equal(34, moved_timer:get_elapsed())
moved_timer:stop()
assert.same({}, minetest.get_meta(pos):to_table().fields)
assert.is_false(minetest.get_node_timer(pos):is_started())
end)
it("calls move callbacks", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, {name = "mesecons_mvps:test_on_move", param2 = 123})
minetest.get_meta(pos):set_string("foo", "bar")
local move_info = {vector.add(pos, dir), world.get_node(pos), pos, minetest.get_meta(pos):to_table()}
mesecon.mvps_push(pos, dir, 1, "")
assert.equal(1, #mesecon._test_moves)
assert.same(move_info, mesecon._test_moves[1])
end)
it("executes autoconnect hooks", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
mesecon.mvps_push(pos, dir, 1, "")
mineunit:execute_globalstep() -- Execute delayed autoconnect hook
assert.equal(2, #mesecon._test_autoconnects)
end)
it("updates moved receptors", function()
local pos1 = {x = 0, y = 0, z = 0}
local pos2 = vector.offset(pos1, 0, 1, 0)
local pos3 = vector.offset(pos1, 2, 0, 0)
local pos4 = vector.offset(pos1, 0, 0, 1)
local dir = {x = 1, y = 0, z = 0}
mesecon._test_place(pos1, "mesecons:test_receptor_on")
mesecon._test_place(pos2, "mesecons:test_conductor_off")
mesecon._test_place(pos3, "mesecons:test_conductor_off")
mesecon._test_place(pos4, "mesecons:test_conductor_off")
mesecon._test_place(vector.add(pos4, dir), "mesecons:test_conductor_off")
mineunit:execute_globalstep() -- Execute receptor_on action
mesecon.mvps_push(pos1, dir, 1, "")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
assert.equal("mesecons:test_conductor_off", world.get_node(pos2).name)
assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name)
assert.equal("mesecons:test_conductor_on", world.get_node(pos4).name)
end)
it("updates moved conductors", function()
local pos1 = {x = 0, y = 0, z = 0}
local pos2 = vector.offset(pos1, 0, 1, 0)
local pos3 = vector.offset(pos1, 0, -1, 0)
local dir = {x = 1, y = 0, z = 0}
mesecon._test_place(pos1, "mesecons:test_conductor_off")
mesecon._test_place(pos2, "mesecons:test_receptor_on")
mesecon._test_place(pos3, "mesecons:test_conductor_off")
mineunit:execute_globalstep() -- Execute receptor_on action
mesecon.mvps_push(pos1, dir, 1, "")
mineunit:execute_globalstep() -- Execute receptor_off action
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos1, dir)).name)
assert.equal("mesecons:test_conductor_off", world.get_node(pos3).name)
mesecon.mvps_pull_all(vector.add(pos1, dir), vector.multiply(dir, -1), 1, "")
mineunit:execute_globalstep() -- Execute receptor_on action
assert.equal("mesecons:test_conductor_on", world.get_node(pos1).name)
assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name)
end)
it("updates moved effectors", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
mesecon._test_place(pos, "mesecons:test_effector")
mesecon._test_place(vector.offset(pos, 0, 1, 0), "mesecons:test_receptor_on")
mesecon._test_place(vector.add(pos, dir), "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
mesecon.mvps_push(pos, dir, 2, "")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2)
mineunit:execute_globalstep() -- Let the component cool down
mesecon.mvps_pull_single(vector.add(pos, dir), vector.multiply(dir, -1), 1, "")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal(tonumber("10000100", 2), world.get_node(pos).param2)
end)
-- Since turnon is called before turnoff when pushing, effectors may be incorrectly turned off.
it("does not overwrite turnon with receptor_off", function()
local pos = {x = 0, y = 0, z = 0}
local dir = {x = 1, y = 0, z = 0}
mesecon._test_place(pos, "mesecons:test_effector")
mesecon._test_place(vector.add(pos, dir), "mesecons:test_conductor_off")
mesecon._test_place(vector.add(pos, vector.multiply(dir, 2)), "mesecons:test_receptor_on")
mineunit:execute_globalstep() -- Execute receptor_on action
mineunit:execute_globalstep() -- Execute activate/change actions
mesecon.mvps_push(pos, dir, 3, "")
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2)
end)
-- mineunit doesn't yet implement minetest.check_for_falling.
pending("causes nodes to fall", function()
end)
end)
describe("protection", function()
teardown(function()
minetest.settings:remove("mesecon.mvps_protection_mode")
end)
after_each(function()
mesecon._test_reset()
world.clear()
end)
local protected_pos = {x = 1, y = 0, z = 0}
mineunit:protect(protected_pos, "Joe")
it("blocks movement", function()
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")})
end)
it("allows owner's movement", function()
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Joe")))
end)
it("'ignore'", function()
minetest.settings:set("mesecon.mvps_protection_mode", "ignore")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")))
end)
it("'normal'", function()
minetest.settings:set("mesecon.mvps_protection_mode", "normal")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")})
assert.is_true((mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")))
end)
it("'compat'", function()
minetest.settings:set("mesecon.mvps_protection_mode", "compat")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")))
end)
it("'restrict'", function()
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
local pos = {x = 0, y = 0, z = 0}
world.set_node(pos, "mesecons:test_conductor_off")
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")})
end)
end)

View File

@ -0,0 +1,3 @@
-- mineunit doesn't yet implement minetest.get_objects_inside_radius
pending("object movement", function()
end)

View File

@ -0,0 +1,15 @@
Credits of sound files:
Note: Most sounds have not been used verbatim, but tweaked a little to be more suitable for the noteblock mod.
* mesecons_noteblock_litecrash.ogg
* License: CC BY 3.0
* by freesound.org user ani_music
* Source: https://freesound.org/people/ani_music/sounds/219612/
Everything else:
Created by Mesecons authors, licensed CC BY 3.0.
--------------------
License links:
* CC BY 3.0: http://creativecommons.org/licenses/by/3.0/

View File

@ -6,8 +6,8 @@ This effector makes a sound if powered and can be used for making music. Normall
<tr><td>Chest or Locked Chest</td><td>Snare</td></tr>
<tr><td>Any tree</td><td>Crash</td></tr>
<tr><td>Any wooden planks</td><td>Lite Crash</td></tr>
<tr><td>Coal Block</td><td>Explosion sound</td></tr>
<tr><td>Lava Source</td><td>Fire sound</td></tr>
<tr><td>Coal Block</td><td>Explosion sound (fixed pitch)</td></tr>
<tr><td>Lava Source</td><td>Fire sound (fixed pitch)</td></tr>
<tr><td>Steel Block</td><td>Piano (high pitch, one octave higher than normal)</td></tr>
<tr><td>Any other block</td><td>Piano (low pitch)</td></tr>
</table>

View File

@ -1,5 +1,7 @@
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_node("mesecons_noteblock:noteblock", {
description = "Noteblock",
description = S("Noteblock"),
tiles = {"mesecons_noteblock.png"},
is_ground_content = false,
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
@ -18,6 +20,7 @@ minetest.register_node("mesecons_noteblock:noteblock", {
mesecon.noteblock_play(pos, node.param2)
end
}},
place_param2 = 11, -- initialize at C note
on_blast = mesecon.on_blastnode,
})
@ -43,7 +46,7 @@ local soundnames = {
"mesecons_noteblock_a",
"mesecons_noteblock_asharp",
"mesecons_noteblock_b",
"mesecons_noteblock_c"
"mesecons_noteblock_c" -- << noteblock is initialized here
}
local node_sounds = {}
@ -72,6 +75,9 @@ mesecon.noteblock_play = function(pos, param2)
pos.y = pos.y-1
local nodeunder = minetest.get_node(pos).name
local soundname = node_sounds[nodeunder]
local use_pitch = true
local pitch
-- Special sounds
if not soundname then
for k,v in pairs(node_sounds_group) do
local g = minetest.get_item_group(nodeunder, k)
@ -81,6 +87,7 @@ mesecon.noteblock_play = function(pos, param2)
end
end
end
-- Piano
if not soundname then
soundname = soundnames[param2]
if not soundname then
@ -90,6 +97,17 @@ mesecon.noteblock_play = function(pos, param2)
if nodeunder == steelblock_nodename then
soundname = soundname.. 2
end
use_pitch = false
end
-- Disable pitch for fire and explode because they'd sound too odd
if soundname == "fire_fire" or soundname == "tnt_explode" then
use_pitch = false
end
if use_pitch then
-- Calculate pitch
-- Adding 1 to param2 because param2=11 is *lowest* pitch sound
local val = (param2+1)%12
pitch = 2^((val-6)/12)
end
pos.y = pos.y+1
if soundname == "fire_fire" then
@ -97,6 +115,6 @@ mesecon.noteblock_play = function(pos, param2)
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)
minetest.sound_play(soundname, {pos = pos, pitch = pitch}, true)
end
end

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_noteblock
### init.lua ###
Noteblock=Sonbloko

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_noteblock
### init.lua ###
Noteblock=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local specs = {
normal = {
offname = "mesecons_pistons:piston_normal_off",
@ -265,7 +267,7 @@ local piston_on_box = {
-- Normal (non-sticky) Pistons:
-- offstate
minetest.register_node("mesecons_pistons:piston_normal_off", {
description = "Piston",
description = S("Piston"),
tiles = {
"mesecons_piston_top.png",
"mesecons_piston_bottom.png",
@ -290,7 +292,7 @@ minetest.register_node("mesecons_pistons:piston_normal_off", {
-- onstate
minetest.register_node("mesecons_pistons:piston_normal_on", {
description = "Activated Piston Base",
description = S("Activated Piston Base"),
drawtype = "nodebox",
tiles = {
"mesecons_piston_top.png",
@ -319,7 +321,7 @@ minetest.register_node("mesecons_pistons:piston_normal_on", {
-- pusher
minetest.register_node("mesecons_pistons:piston_pusher_normal", {
description = "Piston Pusher",
description = S("Piston Pusher"),
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_top.png",
@ -344,7 +346,7 @@ minetest.register_node("mesecons_pistons:piston_pusher_normal", {
-- Sticky ones
-- offstate
minetest.register_node("mesecons_pistons:piston_sticky_off", {
description = "Sticky Piston",
description = S("Sticky Piston"),
tiles = {
"mesecons_piston_top.png",
"mesecons_piston_bottom.png",
@ -369,7 +371,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_off", {
-- onstate
minetest.register_node("mesecons_pistons:piston_sticky_on", {
description = "Activated Sticky Piston Base",
description = S("Activated Sticky Piston Base"),
drawtype = "nodebox",
tiles = {
"mesecons_piston_top.png",
@ -398,7 +400,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_on", {
-- pusher
minetest.register_node("mesecons_pistons:piston_pusher_sticky", {
description = "Sticky Piston Pusher",
description = S("Sticky Piston Pusher"),
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_top.png",

View File

@ -0,0 +1,9 @@
# textdomain: mesecons_pistons
### init.lua ###
Piston=Piŝto
Activated Piston Base=Aktivigita Piŝta Bazo
Piston Pusher=Piŝta Pushero
Sticky Piston=Glueca Piŝto
Activated Sticky Piston Base=Aktivigita Glueca Piŝta Bazo
Sticky Piston Pusher=Glueca Piŝta Puŝilo

View File

@ -0,0 +1,9 @@
# textdomain: mesecons_pistons
### init.lua ###
Piston=
Activated Piston Base=
Piston Pusher=
Sticky Piston=
Activated Sticky Piston Base=
Sticky Piston Pusher=

View File

@ -1,6 +1,8 @@
-- The POWER_PLANT
-- Just emits power. always.
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_node("mesecons_powerplant:power_plant", {
drawtype = "plantlike",
visual_scale = 1,
@ -11,7 +13,7 @@ minetest.register_node("mesecons_powerplant:power_plant", {
walkable = false,
groups = {dig_immediate=3, mesecon = 2},
light_source = minetest.LIGHT_MAX-9,
description="Power Plant",
description=S("Power Plant"),
selection_box = {
type = "fixed",
fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3},

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_powerplant
### init.lua ###
Power Plant=Elektra Planto

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_powerplant
### init.lua ###
Power Plant=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
local pp_box_off = {
type = "fixed",
fixed = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 },
@ -87,7 +89,7 @@ end
mesecon.register_pressure_plate(
"mesecons_pressureplates:pressure_plate_wood",
"Wooden Pressure Plate",
S("Wooden Pressure Plate"),
{"jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off_edges.png"},
{"jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on_edges.png"},
"jeija_pressure_plate_wood_wield.png",
@ -98,7 +100,7 @@ mesecon.register_pressure_plate(
mesecon.register_pressure_plate(
"mesecons_pressureplates:pressure_plate_stone",
"Stone Pressure Plate",
S("Stone Pressure Plate"),
{"jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off_edges.png"},
{"jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on_edges.png"},
"jeija_pressure_plate_stone_wield.png",

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_pressureplates
### init.lua ###
Wooden Pressure Plate=Ligna Prema Plato
Stone Pressure Plate=Ŝtona Prema Plato

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_pressureplates
### init.lua ###
Wooden Pressure Plate=
Stone Pressure Plate=

View File

@ -1,3 +1,5 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- REMOVESTONE
minetest.register_node("mesecons_random:removestone", {
@ -5,7 +7,7 @@ minetest.register_node("mesecons_random:removestone", {
is_ground_content = false,
inventory_image = minetest.inventorycube("jeija_removestone_inv.png"),
groups = {cracky=3},
description="Removestone",
description = S("Removestone"),
sounds = mesecon.node_sound.stone,
mesecons = {effector = {
action_on = function (pos, node)
@ -29,7 +31,7 @@ minetest.register_craft({
-- GHOSTSTONE
minetest.register_node("mesecons_random:ghoststone", {
description="Ghoststone",
description = S("Ghoststone"),
tiles = {"jeija_ghoststone.png"},
is_ground_content = false,
inventory_image = minetest.inventorycube("jeija_ghoststone_inv.png"),

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_random
### init.lua ###
Removestone=Forigŝtono
Ghoststone=Fantomŝtono

View File

@ -0,0 +1,5 @@
# textdomain: mesecons_random
### init.lua ###
Removestone=
Ghoststone=

View File

@ -1,6 +1,8 @@
local S = minetest.get_translator(minetest.get_current_modname())
-- Solar Panel
mesecon.register_node("mesecons_solarpanel:solar_panel", {
description = "Solar Panel",
description = S("Solar Panel"),
drawtype = "nodebox",
tiles = {"mesecons_solarpanel.png"},
inventory_image = "mesecons_solarpanel.png",

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_solarpanel
### init.lua ###
Solar Panel=Suna Panelo

View File

@ -0,0 +1,4 @@
# textdomain: mesecons_solarpanel
### init.lua ###
Solar Panel=

View File

@ -1,10 +1,12 @@
-- Sticky blocks can be used together with pistons or movestones to push / pull
-- structures that are "glued" together using sticky blocks
local S = minetest.get_translator(minetest.get_current_modname())
-- All sides sticky block
minetest.register_node("mesecons_stickyblocks:sticky_block_all", {
-- TODO: Rename to “All-Faces Sticky Block” when other sticky blocks become available
description = "Sticky Block",
description = S("Sticky Block"),
tiles = {"mesecons_stickyblocks_sticky.png"},
is_ground_content = false,
groups = {choppy=3, oddly_breakable_by_hand=2},

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