10 Commits

Author SHA1 Message Date
a38f37d1ee Enforce checks for ignore
It is `buildable_to` so the standard check didn’t work
2020-10-23 20:37:40 +03:00
d356f901a3 Make Lua code area and error label use monospaced font (#541) 2020-10-09 22:28:11 +02:00
6921909100 Restrict Lua controller interrupt IDs (#534)
* Deprecate non-string IIDs
* Restrict tabular IIDs to proper trees
Fixes crash on recursive interrupt ID (#473)
2020-09-21 22:32:25 +03:00
3202bf6786 mesecons_doors: Add MTG steel bar door and trapdoor (#523) 2020-09-19 00:27:47 +03:00
fedbf49372 Noteblock: Fade out fire sound (#527) 2020-09-17 19:30:03 +02:00
9fda51b650 Insulated double corner (#524)
* Add insulated double corner
* Make single corner curved to match double corner
* Remove obsolete regular corner textures
2020-08-24 00:30:57 +03:00
4750925eab Allow admins digging any command block (#525)
Allow admins (i.e. players with the `protection_bypass` privilege) digging any command block
2020-08-15 15:33:11 +03:00
16836b16d6 Make more nodes trigger special noteblock sounds (#506) 2020-08-08 12:22:51 +03:00
c1eccba247 Make sounds ephemeral (#521)
The handles were never used anyway
2020-08-01 16:10:14 +03:00
01332a7ba1 Replace deprecated getpos() calls (#522) 2020-07-31 22:26:58 +02:00
23 changed files with 530 additions and 80 deletions

View File

@ -193,14 +193,23 @@ function mesecon.tablecopy(obj) -- deep copy
return obj return obj
end end
-- Returns whether two values are equal.
-- In tables, keys are compared for identity but values are compared recursively.
-- There is no protection from infinite recursion.
function mesecon.cmpAny(t1, t2) function mesecon.cmpAny(t1, t2)
if type(t1) ~= type(t2) then return false end if type(t1) ~= type(t2) then return false end
if type(t1) ~= "table" and type(t2) ~= "table" then return t1 == t2 end if type(t1) ~= "table" then return t1 == t2 end
-- Check that for each key of `t1` both tables have the same value
for i, e in pairs(t1) do for i, e in pairs(t1) do
if not mesecon.cmpAny(e, t2[i]) then return false end if not mesecon.cmpAny(e, t2[i]) then return false end
end end
-- Check that all keys of `t2` are also keys of `t1` so were checked in the previous loop
for i, _ in pairs(t2) do
if t1[i] == nil then return false end
end
return true return true
end end

View File

@ -8,7 +8,7 @@ mesecon.button_turnoff = function (pos)
return return
end end
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2}) minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2})
minetest.sound_play("mesecons_button_pop", {pos = pos}) minetest.sound_play("mesecons_button_pop", { pos = pos }, true)
local rules = mesecon.rules.buttonlike_get(node) local rules = mesecon.rules.buttonlike_get(node)
mesecon.receptor_off(pos, rules) mesecon.receptor_off(pos, rules)
end end
@ -46,7 +46,7 @@ minetest.register_node("mesecons_button:button_off", {
on_rightclick = function (pos, node) on_rightclick = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
minetest.sound_play("mesecons_button_push", {pos=pos}) minetest.sound_play("mesecons_button_push", { pos = pos }, true)
minetest.get_node_timer(pos):start(1) minetest.get_node_timer(pos):start(1)
end, end,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

View File

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

View File

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

View File

@ -29,6 +29,9 @@ function mesecon.is_mvps_stopper(node, pushdir, stack, stackid)
end end
function mesecon.register_mvps_stopper(nodename, get_stopper) function mesecon.register_mvps_stopper(nodename, get_stopper)
if minetest.registered_nodes[nodename] and minetest.registered_nodes[nodename].buildable_to then
minetest.log("warning", ("Registering a buildable-to node \"%s\" as a mesecon stopper, this is not supported"):format(nodename))
end
if get_stopper == nil then if get_stopper == nil then
get_stopper = true get_stopper = true
end end
@ -71,6 +74,10 @@ function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky)
local np = frontiers[1] local np = frontiers[1]
local nn = minetest.get_node(np) local nn = minetest.get_node(np)
-- Never push into unloaded blocks. Dont try to pull from them, either.
-- TODO: load blocks instead, as with wires.
if nn.name == "ignore" then return nil end
if not node_replaceable(nn.name) then if not node_replaceable(nn.name) then
table.insert(nodes, {node = nn, pos = np}) table.insert(nodes, {node = nn, pos = np})
if #nodes > maximum then return nil end if #nodes > maximum then return nil end
@ -327,10 +334,6 @@ function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor)
end end
end end
-- Never push into unloaded blocks. Dont try to pull from them, either.
-- TODO: load blocks instead, as with wires.
mesecon.register_mvps_stopper("ignore")
mesecon.register_mvps_stopper("doors:door_steel_b_1") mesecon.register_mvps_stopper("doors:door_steel_b_1")
mesecon.register_mvps_stopper("doors:door_steel_t_1") mesecon.register_mvps_stopper("doors:door_steel_t_1")
mesecon.register_mvps_stopper("doors:door_steel_b_2") mesecon.register_mvps_stopper("doors:door_steel_b_2")

View File

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

View File

@ -43,19 +43,33 @@ local soundnames = {
} }
local node_sounds = { local node_sounds = {
["default:glass"] = "mesecons_noteblock_hihat",
["default:stone"] = "mesecons_noteblock_kick",
["default:lava_source"] = "fire_fire", ["default:lava_source"] = "fire_fire",
["default:chest"] = "mesecons_noteblock_snare", ["default:chest"] = "mesecons_noteblock_snare",
["default:tree"] = "mesecons_noteblock_crash", ["default:chest_locked"] = "mesecons_noteblock_snare",
["default:wood"] = "mesecons_noteblock_litecrash",
["default:coalblock"] = "tnt_explode", ["default:coalblock"] = "tnt_explode",
["default:glass"] = "mesecons_noteblock_hihat",
["default:obsidian_glass"] = "mesecons_noteblock_hihat",
}
local node_sounds_group = {
["stone"] = "mesecons_noteblock_kick",
["tree"] = "mesecons_noteblock_crash",
["wood"] = "mesecons_noteblock_litecrash",
} }
mesecon.noteblock_play = function(pos, param2) mesecon.noteblock_play = function(pos, param2)
pos.y = pos.y-1 pos.y = pos.y-1
local nodeunder = minetest.get_node(pos).name local nodeunder = minetest.get_node(pos).name
local soundname = node_sounds[nodeunder] local soundname = node_sounds[nodeunder]
if not soundname then
for k,v in pairs(node_sounds_group) do
local g = minetest.get_item_group(nodeunder, k)
if g ~= 0 then
soundname = v
break
end
end
end
if not soundname then if not soundname then
soundname = soundnames[param2] soundname = soundnames[param2]
if not soundname then if not soundname then
@ -67,5 +81,11 @@ mesecon.noteblock_play = function(pos, param2)
end end
end end
pos.y = pos.y+1 pos.y = pos.y+1
minetest.sound_play(soundname, {pos = pos}) if soundname == "fire_fire" then
-- Smoothly fade out fire sound
local handle = minetest.sound_play(soundname, {pos = pos, loop = true})
minetest.after(3.0, minetest.sound_fade, handle, -1.5, 0.0)
else
minetest.sound_play(soundname, {pos = pos}, true)
end
end end

View File

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

View File

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

View File

@ -11,7 +11,7 @@ mesecon.register_node("mesecons_switch:mesecon_switch", {
else else
mesecon.receptor_off(pos) mesecon.receptor_off(pos)
end end
minetest.sound_play("mesecons_switch", {pos=pos}) minetest.sound_play("mesecons_switch", { pos = pos }, true)
end end
},{ },{
groups = {dig_immediate=2}, groups = {dig_immediate=2},

View File

@ -22,7 +22,7 @@ mesecon.register_node("mesecons_walllever:wall_lever", {
else else
mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node)) mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node))
end end
minetest.sound_play("mesecons_lever", {pos=pos}) minetest.sound_play("mesecons_lever", { pos = pos }, true)
end end
},{ },{
tiles = { tiles = {