230 lines
6.7 KiB
Lua
230 lines
6.7 KiB
Lua
lzr_ambience = {}
|
|
|
|
-- The background/ambience music mod for Lazarr!
|
|
-- Originally this mod only contained pure ambience sounds
|
|
-- but then was switched to use music files instead.
|
|
-- The name `lzr_ambience` is kept for historic reasons,
|
|
-- To the user, the sound files here must be called "music".
|
|
-- Internally, they are called "ambiences".
|
|
|
|
local S = minetest.get_translator("lzr_ambience")
|
|
|
|
-- Gain multiplayer for all sounds (between 0.0 and 1.0)
|
|
local MASTER_GAIN = 1.0
|
|
|
|
local ambiences = {}
|
|
local ambience_aliases = {}
|
|
|
|
local current_singleplayer_ambience = nil -- ambience sound handler. nil if no current ambience
|
|
local current_singleplayer_ambience_id = nil -- ambience type ID (e.g. "village"). nil if uninitialized
|
|
local ambience_active = true -- whether to play ambience
|
|
local ambience_reduced = false -- whether volume of ambience is currently reduced to to sound effect
|
|
local ambience_reduced_timer = nil
|
|
local ambience_play_times = {}
|
|
|
|
lzr_ambience.DEFAULT_AMBIENCE = "village"
|
|
local REDUCED_GAIN = 0.1
|
|
local REDUCED_GAIN_STEP_DOWN = 5
|
|
local REDUCED_GAIN_STEP_UP = 0.2
|
|
|
|
local REPEAT_WRAP = 60000
|
|
|
|
lzr_ambience.reduce_ambience = function(reduce_time)
|
|
ambience_reduced = true
|
|
if ambience_reduced_timer then
|
|
ambience_reduced_timer = math.max(ambience_reduced_timer, reduce_time)
|
|
else
|
|
ambience_reduced_timer = reduce_time
|
|
end
|
|
if current_singleplayer_ambience then
|
|
local ambience = ambiences[current_singleplayer_ambience_id]
|
|
local gain = ambience.gain * REDUCED_GAIN * MASTER_GAIN
|
|
minetest.sound_fade(current_singleplayer_ambience, REDUCED_GAIN_STEP_DOWN, gain)
|
|
end
|
|
end
|
|
|
|
lzr_ambience.unreduce_ambience = function()
|
|
ambience_reduced = false
|
|
ambience_reduced_timer = nil
|
|
if current_singleplayer_ambience then
|
|
local ambience = ambiences[current_singleplayer_ambience_id]
|
|
local gain = ambience.gain * MASTER_GAIN
|
|
minetest.sound_fade(current_singleplayer_ambience, REDUCED_GAIN_STEP_UP, gain)
|
|
end
|
|
end
|
|
|
|
lzr_ambience.register_ambience = function(id, soundname, gain, description)
|
|
ambiences[id] = { soundname = soundname, gain = gain, description = description }
|
|
ambience_play_times[id] = 0
|
|
end
|
|
|
|
lzr_ambience.register_ambience_alias = function(old_name, new_name)
|
|
ambience_aliases[old_name] = new_name
|
|
end
|
|
|
|
local registered_on_ambience_changes = {}
|
|
lzr_ambience.register_on_ambience_change = function(func)
|
|
table.insert(registered_on_ambience_changes, func)
|
|
end
|
|
local function report_ambience_change(new_state)
|
|
for i=1, #registered_on_ambience_changes do
|
|
registered_on_ambience_changes[i](new_state)
|
|
end
|
|
end
|
|
|
|
local function stop_ambience()
|
|
if current_singleplayer_ambience then
|
|
minetest.sound_stop(current_singleplayer_ambience)
|
|
current_singleplayer_ambience = nil
|
|
end
|
|
end
|
|
|
|
function lzr_ambience.ambience_exists(id)
|
|
if ambiences[id] then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function lzr_ambience.get_ambiences()
|
|
local list = {}
|
|
for id,_ in pairs(ambiences) do
|
|
table.insert(list, id)
|
|
end
|
|
table.sort(list, function(t1, t2)
|
|
if t1 == "none" and t2 ~= "none" then
|
|
return true
|
|
elseif t1 ~= "none" and t2 == "none" then
|
|
return false
|
|
else
|
|
local d1 = lzr_ambience.get_ambience_description(t1)
|
|
local d2 = lzr_ambience.get_ambience_description(t2)
|
|
return d1 < d2
|
|
end
|
|
end)
|
|
return list
|
|
end
|
|
|
|
function lzr_ambience.get_ambience_description(id)
|
|
if ambience_aliases[id] then
|
|
id = ambience_aliases[id]
|
|
end
|
|
return ambiences[id].description
|
|
end
|
|
|
|
function lzr_ambience.set_ambience(id, no_play)
|
|
if ambience_aliases[id] then
|
|
id = ambience_aliases[id]
|
|
end
|
|
local ambience = ambiences[id]
|
|
if not ambience then
|
|
minetest.log("error", "[lzr_ambience] set_ambience called with invalid ambience ID ("..tostring(id)..")")
|
|
return false
|
|
end
|
|
minetest.log("info", "[lzr_ambience] Ambience set to: "..tostring(id))
|
|
-- No-op if we already have this ambience active
|
|
if current_singleplayer_ambience_id == id and current_singleplayer_ambience then
|
|
return true
|
|
end
|
|
stop_ambience()
|
|
if id ~= "none" and not no_play and ambience_active then
|
|
local gain
|
|
if ambience_reduced then
|
|
gain = ambience.gain * REDUCED_GAIN * MASTER_GAIN
|
|
else
|
|
gain = ambience.gain * MASTER_GAIN
|
|
end
|
|
local start_time = ambience_play_times[id]
|
|
current_singleplayer_ambience = minetest.sound_play({name=ambience.soundname}, {gain = gain, to_player="singleplayer", loop=true, start_time=start_time})
|
|
end
|
|
current_singleplayer_ambience_id = id
|
|
return true
|
|
end
|
|
|
|
function lzr_ambience.toggle_ambience(save_setting)
|
|
if current_singleplayer_ambience then
|
|
ambience_active = false
|
|
stop_ambience()
|
|
report_ambience_change(ambience_active)
|
|
if save_setting then
|
|
minetest.settings:set_bool("lzr_ambience", false)
|
|
end
|
|
return false
|
|
else
|
|
ambience_active = true
|
|
lzr_ambience.set_ambience(current_singleplayer_ambience_id)
|
|
report_ambience_change(ambience_active)
|
|
if save_setting then
|
|
minetest.settings:set_bool("lzr_ambience", true)
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
|
|
function lzr_ambience.toggle_ambience_by_player(player, save_setting)
|
|
local new_status = lzr_ambience.toggle_ambience(save_setting)
|
|
if new_status then
|
|
lzr_messages.show_message(player, S("Music enabled"), 2)
|
|
return true
|
|
else
|
|
lzr_messages.show_message(player, S("Music disabled"), 2)
|
|
return false
|
|
end
|
|
end
|
|
|
|
function lzr_ambience.is_active()
|
|
return ambience_active
|
|
end
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
if not ambience_active then
|
|
return
|
|
end
|
|
if ambience_reduced and ambience_reduced_timer then
|
|
ambience_reduced_timer = ambience_reduced_timer - dtime
|
|
if ambience_reduced_timer <= 0 then
|
|
lzr_ambience.unreduce_ambience()
|
|
end
|
|
end
|
|
if current_singleplayer_ambience_id then
|
|
ambience_play_times[current_singleplayer_ambience_id] = ambience_play_times[current_singleplayer_ambience_id] + dtime
|
|
if ambience_play_times[current_singleplayer_ambience_id] > REPEAT_WRAP then
|
|
ambience_play_times[current_singleplayer_ambience_id] = 0
|
|
end
|
|
end
|
|
end)
|
|
|
|
local setting = minetest.settings:get_bool("lzr_ambience", true)
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
if setting then
|
|
ambience_active = true
|
|
report_ambience_change(ambience_active)
|
|
lzr_ambience.set_ambience("village")
|
|
else
|
|
ambience_active = false
|
|
report_ambience_change(ambience_active)
|
|
lzr_ambience.set_ambience("village", true)
|
|
end
|
|
end)
|
|
|
|
minetest.register_chatcommand("music", {
|
|
description = S("Toggle music"),
|
|
func = function(name)
|
|
local player = minetest.get_player_by_name(name)
|
|
local new_status = lzr_ambience.toggle_ambience_by_player(player, true)
|
|
if new_status then
|
|
return true, S("Music enabled.")
|
|
else
|
|
return true, S("Music disabled.")
|
|
end
|
|
end,
|
|
})
|
|
|
|
-- Special built-in ambience that is completely silent
|
|
--~ Special entry in music list representing silence
|
|
lzr_ambience.register_ambience("none", nil, nil, S("None"))
|
|
|
|
dofile(minetest.get_modpath("lzr_ambience").."/register.lua")
|