From 954161bf946b21d0dd4f25db6a4f589fccd8794e Mon Sep 17 00:00:00 2001 From: cron Date: Sun, 29 Nov 2020 06:34:53 +0000 Subject: [PATCH] muse: add automatic noteblock player --- clientmods/mods.conf | 1 + clientmods/muse/init.lua | 146 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 clientmods/muse/init.lua diff --git a/clientmods/mods.conf b/clientmods/mods.conf index 9245050b7..825147c3a 100644 --- a/clientmods/mods.conf +++ b/clientmods/mods.conf @@ -39,3 +39,4 @@ load_mod_quint = true load_mod_automt = true load_mod_nlist = true load_mod_crystalkamikaze = true +load_mod_muse = true diff --git a/clientmods/muse/init.lua b/clientmods/muse/init.lua new file mode 100644 index 000000000..482848fb0 --- /dev/null +++ b/clientmods/muse/init.lua @@ -0,0 +1,146 @@ +-- CC0/Unlicense Emilia 2020 + +-- TODO: support noteblocks on different blocktypes +-- denoted with S/W/O/etc. then the tone in a string? +-- TODO: polyphony? +-- TODO: multiple mod support + +muse = {} +muse.playing = nil + +-- assumes tone in param2 +muse.noteblocks = { + "mesecons_noteblock:noteblock" +} + +muse.tracks = { + ["test"] = { + name = "example", + interval = 0.25, -- in seconds + notes = { + 10, + 10 + } + } +} + +local toneblocks = {} + +local tones = {} + +function muse.find_toneblocks(radius) + radius = radius or 20 + + local pos = vector.round(minetest.localplayer:get_pos()) + local nodes = minetest.find_nodes_near(pos, radius, muse.noteblocks) + + for i, v in ipairs(nodes) do + local p2 = minetest.get_node_or_nil(v).param2 + local i = tostring(p2) + + if not toneblocks[i] then + toneblocks[i] = {} + end + + toneblocks[i][#toneblocks[i] + 1] = v + end +end + +function muse.play(note) + if not note then + return + end + + if note == -1 then + return + end + + if type(note) == "string" then + note = tones[note] + end + + local poses = toneblocks[tostring(note)] + if poses then + local pos = poses[1] + + minetest.localplayer:set_pos(pos) + minetest.interact("start_digging", pos) + minetest.interact("stop_digging", pos) + end +end + +function muse.play_track(track) + muse.playing = track + muse.playing.idx = 1 + muse.playing.last = 0 +end + +minetest.register_globalstep(function() + local now = os.clock() + if muse.playing and muse.playing.last + muse.playing.interval <= now then + muse.playing.last = now + local note = muse.playing.notes[muse.playing.idx] + if note then + muse.play(note) + muse.playing.idx = muse.playing.idx + 1 + else + muse.playing = nil + end + end +end) + +local function timestring(seconds) + seconds = math.floor(seconds + 0.5) + local mins = math.floor(seconds / 60) + local secs = seconds % 60 + return string.format("%02d:%02d", mins, secs) +end + +function muse.get_playing_string() + if muse.playing then + return string.format("Currently playing: %s, %d/%d (%s/%s)", + muse.playing.name, + muse.playing.idx, + #muse.playing.notes, + timestring(muse.playing.idx * muse.playing.interval), + timestring(#muse.playing.notes * muse.playing.interval)) + else + return "Nothing is playing" + end +end + +minetest.register_chatcommand("findtones", { + description = "Find tone blocks in the vicinity.", + func = function() + toneblocks = {} + muse.find_toneblocks() + + local len = 0 + for k, v in pairs(toneblocks) do + len = len + 1 + end + + minetest.display_chat_message("Found " .. tostring(len) .. " out of 25 tones") + end +}) + +minetest.register_chatcommand("play", { + description = "Play a musical track", + params = "", + func = function(params) + local track = muse.tracks[params] + if track then + muse.play_track(track) + minetest.display_chat_message("Now playing " .. muse.playing.name) + else + minetest.display_chat_message("Track not found.") + end + end +}) + +minetest.register_chatcommand("playing", { + description = "Show currently playing track and its progress", + func = function() + minetest.display_chat_message(muse.get_playing_string()) + end +})