mirror of
https://github.com/minetest/minetest.git
synced 2024-12-25 07:32:24 +01:00
324 lines
8.8 KiB
Lua
324 lines
8.8 KiB
Lua
local F = minetest.formspec_escape
|
|
|
|
-- hashed node pos -> sound handle
|
|
local played_sounds = {}
|
|
|
|
-- all of these can be set via the formspec
|
|
local meta_keys = {
|
|
-- SimpleSoundSpec
|
|
"sss.name",
|
|
"sss.gain",
|
|
"sss.pitch",
|
|
"sss.fade",
|
|
-- sound parameters
|
|
"sparam.gain",
|
|
"sparam.pitch",
|
|
"sparam.fade",
|
|
"sparam.loop",
|
|
"sparam.pos",
|
|
"sparam.object",
|
|
"sparam.to_player",
|
|
"sparam.exclude_player",
|
|
"sparam.max_hear_distance",
|
|
-- fade
|
|
"fade.step",
|
|
"fade.gain",
|
|
-- other
|
|
"ephemeral",
|
|
}
|
|
|
|
local function get_all_metadata(meta)
|
|
return {
|
|
sss = {
|
|
name = meta:get_string("sss.name"),
|
|
gain = meta:get_string("sss.gain"),
|
|
pitch = meta:get_string("sss.pitch"),
|
|
fade = meta:get_string("sss.fade"),
|
|
},
|
|
sparam = {
|
|
gain = meta:get_string("sparam.gain"),
|
|
pitch = meta:get_string("sparam.pitch"),
|
|
fade = meta:get_string("sparam.fade"),
|
|
loop = meta:get_string("sparam.loop"),
|
|
pos = meta:get_string("sparam.pos"),
|
|
object = meta:get_string("sparam.object"),
|
|
to_player = meta:get_string("sparam.to_player"),
|
|
exclude_player = meta:get_string("sparam.exclude_player"),
|
|
max_hear_distance = meta:get_string("sparam.max_hear_distance"),
|
|
},
|
|
fade = {
|
|
gain = meta:get_string("fade.gain"),
|
|
step = meta:get_string("fade.step"),
|
|
},
|
|
ephemeral = meta:get_string("ephemeral"),
|
|
}
|
|
end
|
|
|
|
local function log_msg(msg)
|
|
minetest.log("action", msg)
|
|
minetest.chat_send_all(msg)
|
|
end
|
|
|
|
local function try_call(f, ...)
|
|
local function log_on_err(success, errmsg, ...)
|
|
if not success then
|
|
log_msg("[soundstuff:jukebox] Call failed: "..errmsg)
|
|
else
|
|
return errmsg, ...
|
|
end
|
|
end
|
|
|
|
return log_on_err(pcall(f, ...))
|
|
end
|
|
|
|
local function show_formspec(pos, player)
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
local md = get_all_metadata(meta)
|
|
|
|
local pos_hash = minetest.hash_node_position(pos)
|
|
local sound_handle = played_sounds[pos_hash]
|
|
|
|
local fs = {}
|
|
local function fs_add(str)
|
|
table.insert(fs, str)
|
|
end
|
|
|
|
fs_add([[
|
|
formspec_version[6]
|
|
size[14,11]
|
|
]])
|
|
|
|
-- SimpleSoundSpec
|
|
fs_add(string.format([[
|
|
container[0.5,0.5]
|
|
box[-0.1,-0.1;4.2,3.2;#EBEBEB20]
|
|
style[*;font=mono,bold]
|
|
label[0,0.25;SimpleSoundSpec]
|
|
style[*;font=mono]
|
|
field[0.00,1.00;4,0.75;sss.name;name;%s]
|
|
field[0.00,2.25;1,0.75;sss.gain;gain;%s]
|
|
field[1.25,2.25;1,0.75;sss.pitch;pitch;%s]
|
|
field[2.50,2.25;1,0.75;sss.fade;fade;%s]
|
|
container_end[]
|
|
field_close_on_enter[sss.name;false]
|
|
field_close_on_enter[sss.gain;false]
|
|
field_close_on_enter[sss.pitch;false]
|
|
field_close_on_enter[sss.fade;false]
|
|
]], F(md.sss.name), F(md.sss.gain), F(md.sss.pitch), F(md.sss.fade)))
|
|
|
|
-- sound parameter table
|
|
fs_add(string.format([[
|
|
container[5.5,0.5]
|
|
box[-0.1,-0.1;4.2,10.2;#EBEBEB20]
|
|
style[*;font=mono,bold]
|
|
label[0,0.25;sound parameter table]
|
|
style[*;font=mono]
|
|
field[0.00,1;1,0.75;sparam.gain;gain;%s]
|
|
field[1.25,1;1,0.75;sparam.pitch;pitch;%s]
|
|
field[2.50,1;1,0.75;sparam.fade;fade;%s]
|
|
field[0,2.25;4,0.75;sparam.loop;loop;%s]
|
|
field[0,3.50;4,0.75;sparam.pos;pos;%s]
|
|
field[0,4.75;4,0.75;sparam.object;object;%s]
|
|
field[0,6.00;4,0.75;sparam.to_player;to_player;%s]
|
|
field[0,7.25;4,0.75;sparam.exclude_player;exclude_player;%s]
|
|
field[0,8.50;4,0.75;sparam.max_hear_distance;max_hear_distance;%s]
|
|
container_end[]
|
|
field_close_on_enter[sparam.gain;false]
|
|
field_close_on_enter[sparam.pitch;false]
|
|
field_close_on_enter[sparam.fade;false]
|
|
field_close_on_enter[sparam.loop;false]
|
|
field_close_on_enter[sparam.pos;false]
|
|
field_close_on_enter[sparam.object;false]
|
|
field_close_on_enter[sparam.to_player;false]
|
|
field_close_on_enter[sparam.exclude_player;false]
|
|
field_close_on_enter[sparam.max_hear_distance;false]
|
|
tooltip[sparam.object;Get a name with the Branding Iron.]
|
|
]], F(md.sparam.gain), F(md.sparam.pitch), F(md.sparam.fade), F(md.sparam.loop),
|
|
F(md.sparam.pos), F(md.sparam.object), F(md.sparam.to_player),
|
|
F(md.sparam.exclude_player), F(md.sparam.max_hear_distance)))
|
|
|
|
-- fade
|
|
fs_add(string.format([[
|
|
container[10.75,3]
|
|
box[-0.1,-0.1;3.2,3.2;#EBEBEB20]
|
|
style[*;font=mono,bold]
|
|
label[0,0.25;fade]
|
|
style[*;font=mono]
|
|
field[0.00,1;1,0.75;fade.step;step;%s]
|
|
field[1.25,1;1,0.75;fade.gain;gain;%s]
|
|
]], F(md.fade.step), F(md.fade.gain)))
|
|
if not sound_handle then
|
|
fs_add([[
|
|
box[0,2;3,0.75;#363636FF]
|
|
label[0.25,2.375;no sound]
|
|
]])
|
|
else
|
|
fs_add([[
|
|
button[0,2;3,0.75;btn_fade;Fade]
|
|
]])
|
|
end
|
|
fs_add([[
|
|
container_end[]
|
|
field_close_on_enter[fade.step;false]
|
|
field_close_on_enter[fade.gain;false]
|
|
]])
|
|
|
|
-- ephemeral
|
|
fs_add(string.format([[
|
|
checkbox[0.5,5;ephemeral;ephemeral;%s]
|
|
]], md.ephemeral))
|
|
|
|
-- play/stop and release buttons
|
|
if not sound_handle then
|
|
fs_add([[
|
|
container[10.75,0.5]
|
|
button[0,0;3,0.75;btn_play;Play]
|
|
container_end[]
|
|
]])
|
|
else
|
|
fs_add([[
|
|
container[10.75,0.5]
|
|
button[0,0;3,0.75;btn_stop;Stop]
|
|
button[0,1;3,0.75;btn_release;Release]
|
|
container_end[]
|
|
]])
|
|
end
|
|
|
|
-- save and quit button
|
|
fs_add([[
|
|
button_exit[10.75,10;3,0.75;btn_save_quit;Save & Quit]
|
|
]])
|
|
|
|
minetest.show_formspec(player:get_player_name(), "soundstuff:jukebox@"..pos:to_string(),
|
|
table.concat(fs))
|
|
end
|
|
|
|
minetest.register_node("soundstuff:jukebox", {
|
|
description = "Jukebox\nAllows to play arbitrary sounds.",
|
|
tiles = {"soundstuff_jukebox.png"},
|
|
groups = {dig_immediate = 2},
|
|
|
|
on_construct = function(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
-- SimpleSoundSpec
|
|
meta:set_string("sss.name", "")
|
|
meta:set_string("sss.gain", "")
|
|
meta:set_string("sss.pitch", "")
|
|
meta:set_string("sss.fade", "")
|
|
-- sound parameters
|
|
meta:set_string("sparam.gain", "")
|
|
meta:set_string("sparam.pitch", "")
|
|
meta:set_string("sparam.fade", "")
|
|
meta:set_string("sparam.loop", "")
|
|
meta:set_string("sparam.pos", pos:to_string())
|
|
meta:set_string("sparam.object", "")
|
|
meta:set_string("sparam.to_player", "")
|
|
meta:set_string("sparam.exclude_player", "")
|
|
meta:set_string("sparam.max_hear_distance", "")
|
|
-- fade
|
|
meta:set_string("fade.gain", "")
|
|
meta:set_string("fade.step", "")
|
|
-- other
|
|
meta:set_string("ephemeral", "")
|
|
|
|
meta:mark_as_private(meta_keys)
|
|
end,
|
|
|
|
on_rightclick = function(pos, _node, clicker, _itemstack, _pointed_thing)
|
|
show_formspec(pos, clicker)
|
|
end,
|
|
})
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname:sub(1, 19) ~= "soundstuff:jukebox@" then
|
|
return false
|
|
end
|
|
|
|
local pos = vector.from_string(formname, 20)
|
|
if not pos or pos ~= pos:round() then
|
|
minetest.log("error", "[soundstuff:jukebox] Invalid formname.")
|
|
return true
|
|
end
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
for _, k in ipairs(meta_keys) do
|
|
if fields[k] then
|
|
meta:set_string(k, fields[k])
|
|
end
|
|
end
|
|
meta:mark_as_private(meta_keys)
|
|
|
|
local pos_hash = minetest.hash_node_position(pos)
|
|
local sound_handle = played_sounds[pos_hash]
|
|
|
|
if not sound_handle then
|
|
if fields.btn_play then
|
|
local md = get_all_metadata(meta)
|
|
|
|
local sss = {
|
|
name = md.sss.name,
|
|
gain = tonumber(md.sss.gain),
|
|
pitch = tonumber(md.sss.pitch),
|
|
fade = tonumber(md.sss.fade),
|
|
}
|
|
local sparam = {
|
|
gain = tonumber(md.sparam.gain),
|
|
pitch = tonumber(md.sparam.pitch),
|
|
fade = tonumber(md.sparam.fade),
|
|
loop = minetest.is_yes(md.sparam.loop),
|
|
pos = vector.from_string(md.sparam.pos),
|
|
object = testtools.get_branded_object(md.sparam.object),
|
|
to_player = md.sparam.to_player,
|
|
exclude_player = md.sparam.exclude_player,
|
|
max_hear_distance = tonumber(md.sparam.max_hear_distance),
|
|
}
|
|
local ephemeral = minetest.is_yes(md.ephemeral)
|
|
|
|
log_msg(string.format(
|
|
"[soundstuff:jukebox] Playing sound: minetest.sound_play(%s, %s, %s)",
|
|
string.format("{name=\"%s\", gain=%s, pitch=%s, fade=%s}",
|
|
sss.name, sss.gain, sss.pitch, sss.fade),
|
|
string.format("{gain=%s, pitch=%s, fade=%s, loop=%s, pos=%s, "
|
|
.."object=%s, to_player=\"%s\", exclude_player=\"%s\", max_hear_distance=%s}",
|
|
sparam.gain, sparam.pitch, sparam.fade, sparam.loop, sparam.pos,
|
|
sparam.object and "<objref>", sparam.to_player, sparam.exclude_player,
|
|
sparam.max_hear_distance),
|
|
tostring(ephemeral)))
|
|
|
|
sound_handle = try_call(minetest.sound_play, sss, sparam, ephemeral)
|
|
|
|
played_sounds[pos_hash] = sound_handle
|
|
show_formspec(pos, player)
|
|
end
|
|
|
|
else
|
|
if fields.btn_stop then
|
|
log_msg("[soundstuff:jukebox] Stopping sound: minetest.sound_stop(<handle>)")
|
|
|
|
try_call(minetest.sound_stop, sound_handle)
|
|
|
|
elseif fields.btn_release then
|
|
log_msg("[soundstuff:jukebox] Releasing handle.")
|
|
|
|
played_sounds[pos_hash] = nil
|
|
show_formspec(pos, player)
|
|
|
|
elseif fields.btn_fade then
|
|
local md = get_all_metadata(meta)
|
|
|
|
local step = tonumber(md.fade.step)
|
|
local gain = tonumber(md.fade.gain)
|
|
|
|
log_msg(string.format(
|
|
"[soundstuff:jukebox] Fading sound: minetest.sound_fade(<handle>, %s, %s)",
|
|
step, gain))
|
|
|
|
try_call(minetest.sound_fade, sound_handle, step, gain)
|
|
end
|
|
end
|
|
|
|
return true
|
|
end)
|