2024-12-10 02:34:33 +01:00

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")