diff --git a/README.TXT b/README.TXT index 47c6320..c22f25f 100644 --- a/README.TXT +++ b/README.TXT @@ -1,4 +1,4 @@ -Coconut Collection - 12/22/2021 Alpha6 +Coconut Collection - 12/22/2021 Beta2 A game heavily inspired by "Coconut Hut" for the Ouya, it's a competetive 2-player game where you collect coconuts and sell them in order to gain cash. @@ -25,6 +25,8 @@ main - made specifically for this game, MIT coconut - also made for this game, MIT +mpd - by orwell, relicensed under MIT + telephone - a heavily modified version of my telephone mod that I wrote a couple of months ago, MIT indsutrial_decor - a small mod that I wrote back in 2018, adds a few decor blocks; nothing special, MIT diff --git a/mods/mpd/depends.txt b/mods/mpd/depends.txt new file mode 100644 index 0000000..fdf44a0 --- /dev/null +++ b/mods/mpd/depends.txt @@ -0,0 +1 @@ +vote? diff --git a/mods/mpd/init.lua b/mods/mpd/init.lua new file mode 100644 index 0000000..5403f7e --- /dev/null +++ b/mods/mpd/init.lua @@ -0,0 +1,214 @@ + +mpd={} + + +mpd.pause_between_songs=tonumber(minetest.settings:get("mpd_pause_between_songs")) or 30 + +--end config + +mpd.modpath=minetest.get_modpath("mpd") +if not mpd.modpath then + error("mpd mod folder has to be named 'mpd'!") +end +--{name, length, gain~1} +mpd.songs = {} +local sfile, sfileerr=io.open(mpd.modpath..DIR_DELIM.."songs.txt") +if not sfile then error("Error opening songs.txt: "..sfileerr) end +for linent in sfile:lines() do + -- trim leading and trailing spaces away + local line = string.match(linent, "^%s*(.-)%s*$") + if line~="" and string.sub(line,1,1)~="#" then + local name, timeMinsStr, timeSecsStr, gainStr, title = string.match(line, "^(%S+)%s+(%d+):([%d%.]+)%s+([%d%.]+)%s*(.*)$") + local timeMins, timeSecs, gain = tonumber(timeMinsStr), tonumber(timeSecsStr), tonumber(gainStr) + if title=="" then title = name end + if name and timeMins and timeSecs and gain then + mpd.songs[#mpd.songs+1]={name=name, length=timeMins*60+timeSecs, lengthhr=timeMinsStr..":"..timeSecsStr, gain=gain, title=title} + else + minetest.log("warning", "[mpd] Misformatted song entry in songs.txt: "..line) + end + end +end +sfile:close() + +if #mpd.songs==0 then + print("[mpd]no songs registered, not doing anything") + return +end + +mpd.storage = minetest.get_mod_storage() + +mpd.handles={} + +mpd.playing=false +mpd.id_playing=nil +mpd.song_time_left=nil +mpd.time_next=3 --secs +mpd.id_last_played=nil + +minetest.register_globalstep(function(dtime) + if mpd.playing then + if mpd.song_time_left<=0 then + mpd.stop_song() + mpd.time_next=mpd.pause_between_songs + else + mpd.song_time_left=mpd.song_time_left-dtime + end + elseif mpd.time_next then + if mpd.time_next<=0 then + mpd.next_song() + else + mpd.time_next=mpd.time_next-dtime + end + end +end) +mpd.play_song=function(id) + if mpd.playing then + mpd.stop_song() + end + local song=mpd.songs[id] + if not song then return end + for _,player in ipairs(minetest.get_connected_players()) do + local pname=player:get_player_name() + local pvolume=tonumber(mpd.storage:get_string("vol_"..pname)) + if not pvolume then pvolume=1 end + if pvolume>0 then + local handle = minetest.sound_play(song.name, {to_player=pname, gain=song.gain*pvolume}) + if handle then + mpd.handles[pname]=handle + end + end + end + mpd.playing=id + --adding 2 seconds as security + mpd.song_time_left = song.length + 2 +end +mpd.stop_song=function() + for pname, handle in pairs(mpd.handles) do + minetest.sound_stop(handle) + end + mpd.id_last_played=mpd.playing + mpd.playing=nil + mpd.handles={} + mpd.time_next=nil +end + +mpd.next_song=function() + local next + repeat + next=math.random(1,#mpd.songs) + until #mpd.songs==1 or next~=mpd.id_last_played + mpd.play_song(next) +end + +mpd.song_human_readable=function(id) + if not tonumber(id) then return "" end + local song=mpd.songs[id] + if not song then return "" end + return id..": "..song.title.." ["..song.lengthhr.."]" +end + +minetest.register_privilege("mpd", "may control the music player daemon (mpd) mod") + +minetest.register_chatcommand("mpd_stop", { + params = "", + description = "Stop the song currently playing", + privs = {mpd=true}, + func = function(name, param) + mpd.stop_song() + end, +}) +minetest.register_chatcommand("mpd_list", { + params = "", + description = "List all available songs and their IDs", + privs = {mpd=true}, + func = function(name, param) + for k,v in ipairs(mpd.songs) do + minetest.chat_send_player(name, mpd.song_human_readable(k)) + end + end, +}) +minetest.register_chatcommand("mpd_play", { + params = "", + description = "Play the songs with the given ID (see ids with /mpd_list)", + privs = {mpd=true}, + func = function(name, param) + if param=="" then + mpd.next_song() + return true,"Playing: "..mpd.song_human_readable(mpd.playing) + end + id=tonumber(param) + if id and id>0 and id<=#mpd.songs then + mpd.play_song(id) + return true,"Playing: "..mpd.song_human_readable(id) + end + return false, "Invalid song ID!" + end, +}) +minetest.register_chatcommand("mpd_what", { + params = "", + description = "Display the currently played song.", + privs = {mpd=true}, + func = function(name, param) + if not mpd.playing then + if mpd.time_next and mpd.time_next~=0 then + return true,"Nothing playing, "..math.floor(mpd.time_next or 0).." sec. left until next song." + else + return true,"Nothing playing." + end + end + return true,"Playing: "..mpd.song_human_readable(mpd.playing).."\nTime Left: "..math.floor(mpd.song_time_left or 0).." sec." + end, +}) +minetest.register_chatcommand("mpd_next", { + params = "[seconds]", + description = "Start the next song, either immediately (no parameters) or after n seconds.", + privs = {mpd=true}, + func = function(name, param) + mpd.stop_song() + if param and tonumber(param) then + mpd.time_next=tonumber(param) + return true,"Next song in "..param.." seconds!" + else + mpd.next_song() + return true,"Next song started!" + end + end, +}) +minetest.register_chatcommand("mvolume", { + params = "[volume level (0-1)]", + description = "Set your background music volume. Use /mvolume 0 to turn off background music for you. Without parameters, show your current setting.", + privs = {}, + func = function(pname, param) + if not param or param=="" then + local pvolume=tonumber(mpd.storage:get_string("vol_"..pname)) + if not pvolume then pvolume=0.5 end + if pvolume>0 then + return true, "Your music volume is set to "..pvolume.."." + else + if mpd.handles[pname] then + minetest.sound_stop(mpd.handles[pname]) + end + return true, "Background music is disabled for you. Use '/mvolume 1' to enable it again." + end + end + local pvolume=tonumber(param) + if not pvolume then + return false, "Invalid usage: /mvolume [volume level (0-1)]" + end + pvolume = math.min(pvolume, 1) + pvolume = math.max(pvolume, 0) + mpd.storage:set_string("vol_"..pname, pvolume) + if pvolume>0 then + return true, "Music volume set to "..pvolume..". Change will take effect when the next song starts." + else + if mpd.handles[pname] then + minetest.sound_stop(mpd.handles[pname]) + end + return true, "Disabled background music for you. Use /mvolume to enable it again." + end + end, +}) + +if vote then + dofile(mpd.modpath..DIR_DELIM.."vote.lua") +end diff --git a/mods/mpd/mod.conf b/mods/mpd/mod.conf new file mode 100644 index 0000000..f912066 --- /dev/null +++ b/mods/mpd/mod.conf @@ -0,0 +1 @@ +name = mpd diff --git a/mods/mpd/readme.txt b/mods/mpd/readme.txt new file mode 100644 index 0000000..5bd7f68 --- /dev/null +++ b/mods/mpd/readme.txt @@ -0,0 +1,44 @@ + +### mpd Mod for Minetest +(c) 2017 orwell96 +This mod is licensed under the LGPL 2.1 license. + +Adds an easy but powerful background music backend. + +## Usage: + +For all players: +/mvolume +Set your individual music volume or disable background music (/mvolume 0). Saved across server restarts. +/mpd_list: list available music + +With mpd privilege: +/mpd_play : play a song +/mpd_stop: stop the current song. Unless /mpd_play or /mpd_next are invoked, no more music is played +/mpd_next [time]: Play the next song after [time] seconds, immediately if omitted. + +## Votes: +This mod integrates with the [vote] mod by rubenwardy (https://github.com/minetest-mods/vote) +/vote_mpd_next - vote to start next song +/vote_mpd_play - Vote to play certain sing + +## Music credits: + +StrangelyBeautifulShort 3:01 0.7 +AvalonShort 2:58 1.4 +EtherealShort 3:04 0.7 +FarawayShort 3:05 0.7 +-> Music from [ambience] mod +-> Author is Amethystium . + +eastern_feeling 3:51 1.0 +-> created by Jordach. It can be found in the BFD subgame. License is GPLv3 (license of BFD). + +bensound_deepblue 4:48 1.0 +bensound_ofeliasdream 4:59 1.0 +bensound_slowmotion 3:26 1.0 +-> (c) bensound (AFAIK public domain) + +rainymemory 2:10 1.0 +anonnp4014 2:30 1.6 +-> (c) Deemo collection (game music collection) diff --git a/mods/mpd/settingtypes.txt b/mods/mpd/settingtypes.txt new file mode 100644 index 0000000..e711c02 --- /dev/null +++ b/mods/mpd/settingtypes.txt @@ -0,0 +1,3 @@ +# How many seconds MPD waits before starting the next song +mpd_pause_between_songs (Pause between songs) int 30 0 3600 + diff --git a/mods/mpd/songs.txt b/mods/mpd/songs.txt new file mode 100644 index 0000000..639174b --- /dev/null +++ b/mods/mpd/songs.txt @@ -0,0 +1,3 @@ +#File Name Time Gain Title +tropicalbreeze 1:13 0.7 Tropical Breeze by Flan + diff --git a/mods/mpd/sounds/tropicalbreeze.ogg b/mods/mpd/sounds/tropicalbreeze.ogg new file mode 100644 index 0000000..5755679 Binary files /dev/null and b/mods/mpd/sounds/tropicalbreeze.ogg differ diff --git a/mods/mpd/vote.lua b/mods/mpd/vote.lua new file mode 100644 index 0000000..d1a2ff3 --- /dev/null +++ b/mods/mpd/vote.lua @@ -0,0 +1,68 @@ +--mpd +--vote.lua - vote module to change songs + +function mpd.vote_play(name, param) + id=tonumber(param) + if id and id>0 and id<=#mpd.songs then + vote.new_vote(name, { + description = "Play "..mpd.song_human_readable(id), + help = "/yes or /no", + duration = 20, + perc_needed = 0.4, + + on_result = function(self, result, results) + if result == "yes" then + minetest.chat_send_all("Vote to play " .. mpd.song_human_readable(id) .. " passed " .. + #results.yes .. " to " .. #results.no) + mpd.play_song(id) + else + minetest.chat_send_all("Vote to play " .. mpd.song_human_readable(id) .. " failed " .. + #results.yes .. " to " .. #results.no) + end + end, + + on_vote = function(self, name, value) + minetest.chat_send_all(name .. " voted " .. value .. " to '" .. + self.description .. "'") + end, + }) + return true + end + return false,"Invalid song ID! See available song IDs using /mpd_list" +end + +minetest.register_chatcommand("vote_mpd_play", { + func = mpd.vote_play +}) + +function mpd.vote_next(name, param) + vote.new_vote(name, { + description = "Play next song", + help = "/yes or /no", + duration = 20, + perc_needed = 0.4, + + on_result = function(self, result, results) + minetest.chat_send_all(result..dump(results)) + if result == "yes" then + minetest.chat_send_all("Vote to play next song passed " .. + #results.yes .. " to " .. #results.no) + mpd.next_song() + else + minetest.chat_send_all("Vote to play next song failed " .. + #results.yes .. " to " .. #results.no) + end + end, + + on_vote = function(self, name, value) + minetest.chat_send_all(name .. " voted " .. value .. " to '" .. + self.description .. "'") + end + }) + return true +end + +minetest.register_chatcommand("vote_mpd_next", { + func = mpd.vote_next +}) +