init.lua 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. ambience = {}
  2. -- override default water sounds
  3. minetest.override_item("default:water_source", { sounds = {} })
  4. minetest.override_item("default:water_flowing", { sounds = {} })
  5. minetest.override_item("default:river_water_source", { sounds = {} })
  6. minetest.override_item("default:river_water_flowing", { sounds = {} })
  7. -- settings
  8. local SOUNDVOLUME = 1.0
  9. local MUSICVOLUME = 1.0
  10. local play_music = minetest.settings:get_bool("ambience_music") ~= false
  11. local pplus = minetest.get_modpath("playerplus")
  12. local radius = 6
  13. local playing = {}
  14. local sound_sets = {} -- all the sounds and their settings
  15. local sound_set_order = {} -- needed because pairs loops randomly through tables
  16. local set_nodes = {} -- all the nodes needed for sets
  17. -- global functions
  18. ambience.add_set = function(set_name, def)
  19. if set_name and def then
  20. sound_sets[set_name] = {
  21. frequency = def.frequency or 50,
  22. sounds = def.sounds,
  23. sound_check = def.sound_check,
  24. nodes = def.nodes,
  25. }
  26. -- add set name to the sound_set_order table
  27. local can_add = true
  28. for i = 1, #sound_set_order do
  29. if sound_set_order[i] == set_name then
  30. can_add = false
  31. end
  32. end
  33. if can_add then
  34. table.insert(sound_set_order, set_name)
  35. end
  36. -- add any missing nodes to the set_nodes table
  37. if def.nodes then
  38. for i = 1, #def.nodes do
  39. can_add = def.nodes[i]
  40. for j = 1, #set_nodes do
  41. if def.nodes[i] == set_nodes[j] then
  42. can_add = false
  43. end
  44. end
  45. if can_add then
  46. table.insert(set_nodes, can_add)
  47. end
  48. end
  49. end
  50. end
  51. end
  52. ambience.get_set = function(set_name)
  53. if sound_sets[set_name] then
  54. return sound_sets[set_name]
  55. end
  56. end
  57. ambience.del_set = function(set_name)
  58. sound_sets[set_name] = nil
  59. local can_del = false
  60. for i = 1, #sound_set_order do
  61. if sound_set_order[i] == set_name then
  62. can_del = i
  63. end
  64. end
  65. if can_del then
  66. table.remove(sound_set_order, can_del)
  67. end
  68. end
  69. -- plays music and selects sound set
  70. local get_ambience = function(player, tod, name)
  71. -- play server or local music if available
  72. if play_music and playing[name] then
  73. -- play at midnight
  74. if tod >= 0.0 and tod <= 0.01 then
  75. if not playing[name].music then
  76. playing[name].music = minetest.sound_play("ambience_music", {
  77. to_player = player:get_player_name(),
  78. gain = MUSICVOLUME
  79. })
  80. end
  81. elseif tod > 0.1 and playing[name].music then
  82. playing[name].music = nil
  83. end
  84. end
  85. -- get foot and head level nodes at player position
  86. local pos = player:get_pos()
  87. pos.y = pos.y + 1.4 -- head level
  88. local nod_head = pplus and playerplus[name].nod_head or minetest.get_node(pos).name
  89. pos.y = pos.y - 1.2 -- foot level
  90. local nod_feet = pplus and playerplus[name].nod_feet or minetest.get_node(pos).name
  91. pos.y = pos.y - 0.2 -- reset pos
  92. -- get all set nodes around player
  93. local ps, cn = minetest.find_nodes_in_area(
  94. {x = pos.x - radius, y = pos.y - radius, z = pos.z - radius},
  95. {x = pos.x + radius, y = pos.y + radius, z = pos.z + radius}, set_nodes)
  96. -- loop through sets in order and choose one that meets it's conditions
  97. for n = 1, #sound_set_order do
  98. local set = sound_sets[ sound_set_order[n] ]
  99. if set and set.sound_check then
  100. local set_name, gain = set.sound_check({
  101. player = player,
  102. pos = pos,
  103. tod = tod,
  104. totals = cn,
  105. positions = ps,
  106. head_node = nod_head,
  107. feet_node = nod_feet
  108. })
  109. if set_name then
  110. return set_name, gain
  111. end
  112. end
  113. end
  114. end
  115. local timer = 0
  116. local random = math.random
  117. -- player routine
  118. minetest.register_globalstep(function(dtime)
  119. -- every 1 second
  120. timer = timer + dtime
  121. if timer < 1 then return end
  122. timer = 0
  123. local players = minetest.get_connected_players()
  124. local player_name, number, chance, ambience, handler
  125. local tod = minetest.get_timeofday()
  126. for n = 1, #players do
  127. player_name = players[n]:get_player_name()
  128. --local t1 = os.clock()
  129. local set_name, MORE_GAIN = get_ambience(players[n], tod, player_name)
  130. --print(string.format("elapsed time: %.4f\n", os.clock() - t1))
  131. if set_name then
  132. -- stop sound if another set active
  133. if playing[player_name]
  134. and playing[player_name].handler then
  135. if playing[player_name].sound ~= set_name
  136. or (playing[player_name].sound == set_name
  137. and playing[player_name].gain ~= MORE_GAIN) then
  138. minetest.sound_stop(playing[player_name].handler)
  139. playing[player_name].sound = nil
  140. playing[player_name].handler = nil
  141. playing[player_name].gain = nil
  142. else
  143. return
  144. end
  145. end
  146. -- choose random sound from set selected
  147. number = random(1, #sound_sets[set_name].sounds)
  148. ambience = sound_sets[set_name].sounds[number]
  149. math.randomseed(tod + number)
  150. chance = random(1, 1000)
  151. if chance < sound_sets[set_name].frequency then
  152. handler = minetest.sound_play(ambience.name, {
  153. to_player = player_name,
  154. gain = ((ambience.gain or 0.3) + (MORE_GAIN or 0)) * SOUNDVOLUME
  155. })
  156. --print ("playing... " .. ambience.name .. " (" .. chance .. " < "
  157. -- .. sound_sets[set_name].frequency .. ") @ ", MORE_GAIN)
  158. if handler then
  159. playing[player_name] = playing[player_name] or {}
  160. playing[player_name].handler = handler
  161. playing[player_name].sound = set_name
  162. playing[player_name].gain = MORE_GAIN
  163. minetest.after(ambience.length, function(args)
  164. local player_name = args[2]
  165. if playing[player_name]
  166. and playing[player_name].handler
  167. and playing[player_name].sound == set_name then
  168. minetest.sound_stop(playing[player_name].handler)
  169. playing[player_name].sound = nil
  170. playing[player_name].handler = nil
  171. playing[player_name].gain = nil
  172. end
  173. end, {ambience, player_name})
  174. end
  175. end
  176. end
  177. end
  178. end)
  179. -- set volume commands
  180. minetest.register_chatcommand("svol", {
  181. params = "<svol>",
  182. description = "set sound volume (0.1 to 1.0)",
  183. privs = {server = true},
  184. func = function(name, param)
  185. SOUNDVOLUME = tonumber(param) or SOUNDVOLUME
  186. if SOUNDVOLUME < 0.1 then SOUNDVOLUME = 0.1 end
  187. if SOUNDVOLUME > 1.0 then SOUNDVOLUME = 1.0 end
  188. return true, "Sound volume set to " .. SOUNDVOLUME
  189. end,
  190. })
  191. minetest.register_chatcommand("mvol", {
  192. params = "<mvol>",
  193. description = "set music volume (0.1 to 1.0)",
  194. privs = {server = true},
  195. func = function(name, param)
  196. MUSICVOLUME = tonumber(param) or MUSICVOLUME
  197. -- ability to stop music just as it begins
  198. if MUSICVOLUME == 0 and playing[name].music then
  199. minetest.sound_stop(playing[name].music)
  200. end
  201. if MUSICVOLUME < 0.1 then MUSICVOLUME = 0.1 end
  202. if MUSICVOLUME > 1.0 then MUSICVOLUME = 1.0 end
  203. return true, "Music volume set to " .. MUSICVOLUME
  204. end,
  205. })
  206. -- load default sound sets
  207. dofile(minetest.get_modpath("ambience") .. "/soundsets.lua")
  208. print("[MOD] Ambience Lite loaded")