-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.lua
367 lines (247 loc) · 8.46 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
-- global
ambience = {}
-- settings
local SOUNDVOLUME = 1.0
local MUSICVOLUME = 0.6
local MUSICINTERVAL = 60 * 20
local play_music = minetest.settings:get_bool("ambience_music") ~= false
local radius = 6
local playing = {} -- user settings, timers and current set playing
local sound_sets = {} -- all the sounds and their settings
local sound_set_order = {} -- needed because pairs loops randomly through tables
local set_nodes = {} -- all the nodes needed for sets
-- translation
local S = minetest.get_translator("ambience")
-- add set to list
function ambience.add_set(set_name, def)
if not set_name or not def then return end
sound_sets[set_name] = {
frequency = def.frequency or 50,
sounds = def.sounds,
sound_check = def.sound_check,
nodes = def.nodes
}
-- add set name to the sound_set_order table
local can_add = true
for i = 1, #sound_set_order do
if sound_set_order[i] == set_name then can_add = false end
end
if can_add then table.insert(sound_set_order, set_name) end
-- add any missing nodes to the set_nodes table
if def.nodes then
for i = 1, #def.nodes do
can_add = def.nodes[i]
for j = 1, #set_nodes do
if def.nodes[i] == set_nodes[j] then can_add = false end
end
if can_add then table.insert(set_nodes, can_add) end
end
end
end
-- return set from list using name
function ambience.get_set(set_name)
return sound_sets[set_name]
end
-- remove set from list
function ambience.del_set(set_name)
sound_sets[set_name] = nil
local can_del = false
for i = 1, #sound_set_order do
if sound_set_order[i] == set_name then can_del = i end
end
if can_del then table.remove(sound_set_order, can_del) end
end
-- return node total belonging to a specific group:
function ambience.group_total(ntab, ngrp)
local tot = 0
local def, grp
for _,n in pairs(ntab) do
def = minetest.registered_nodes[_]
grp = def and def.groups and def.groups[ngrp]
if grp and grp > 0 then
tot = tot + n
end
end
return tot
end
-- setup table when player joins
minetest.register_on_joinplayer(function(player)
if player then
local name = player:get_player_name()
local meta = player:get_meta()
playing[name] = {
mvol = tonumber(meta:get_string("ambience.mvol")) or MUSICVOLUME,
svol = tonumber(meta:get_string("ambience.svol")) or SOUNDVOLUME,
timer = 0,
music = 0,
music_handler = nil
}
end
end)
-- remove table when player leaves
minetest.register_on_leaveplayer(function(player)
if player then playing[player:get_player_name()] = nil end
end)
-- plays music and selects sound set
local function get_ambience(player, tod, name)
-- if enabled and not already playing, play local/server music on interval check
if play_music and playing[name] and playing[name].mvol > 0 then
-- increase music time interval
playing[name].music = playing[name].music + 1
-- play music on interval check
if playing[name].music > MUSICINTERVAL and playing[name].music_handler == nil then
playing[name].music_handler = minetest.sound_play("ambience_music", {
to_player = name,
gain = playing[name].mvol
})
playing[name].music = 0 -- reset interval
end
--print("-- music timer", playing[name].music .. "/" .. MUSICINTERVAL)
end
-- get foot and head level nodes at player position
local pos = player:get_pos() ; if not pos then return end
local prop = player:get_properties()
local eyeh = prop.eye_height or 1.47 -- eye level with fallback
pos.y = pos.y + eyeh -- head level
local nod_head = minetest.get_node(pos).name
pos.y = (pos.y - eyeh) + 0.2 -- foot level
local nod_feet = minetest.get_node(pos).name
pos.y = pos.y - 0.2 -- reset pos
-- get all set nodes around player
local ps, cn = minetest.find_nodes_in_area(
{x = pos.x - radius, y = pos.y - radius, z = pos.z - radius},
{x = pos.x + radius, y = pos.y + radius, z = pos.z + radius}, set_nodes)
-- loop through sets in order and choose first that meets conditions set
for n = 1, #sound_set_order do
local set = sound_sets[ sound_set_order[n] ]
if set and set.sound_check then
-- get biome data
local bdata = minetest.get_biome_data(pos)
local biome = bdata and minetest.get_biome_name(bdata.biome) or ""
-- pass settings to set function for condition check
local set_name, gain = set.sound_check({
player = player,
pos = pos,
tod = tod,
totals = cn,
positions = ps,
head_node = nod_head,
feet_node = nod_feet,
biome = biome
})
-- if conditions met return set name and gain value
if set_name then return set_name, gain end
end
end
return nil, nil
end
-- players routine
local timer = 0
local random = math.random
minetest.register_globalstep(function(dtime)
local players = minetest.get_connected_players()
local pname
-- reduce sound timer for each player and stop/reset when needed
for _, player in pairs(players) do
pname = player:get_player_name()
if playing[pname] and playing[pname].timer > 0 then
playing[pname].timer = playing[pname].timer - dtime
if playing[pname].timer <= 0 then
if playing[pname].handler then
minetest.sound_stop(playing[pname].handler)
end
playing[pname].set = nil
playing[pname].gain = nil
playing[pname].handler = nil
end
end
end
-- one second timer
timer = timer + dtime ; if timer < 1 then return end ; timer = 0
local number, chance, ambience, handler, ok
local tod = minetest.get_timeofday()
-- loop through players
for _, player in pairs(players) do
pname = player:get_player_name()
local set_name, MORE_GAIN = get_ambience(player, tod, pname)
ok = playing[pname] -- everything starts off ok if player found
-- are we playing something already?
if ok and playing[pname].handler then
-- stop current sound if another set active or gain changed
if playing[pname].set ~= set_name
or playing[pname].gain ~= MORE_GAIN then
--print ("-- change stop", set_name, playing[pname].handler)
minetest.sound_stop(playing[pname].handler)
playing[pname].set = nil
playing[pname].gain = nil
playing[pname].handler = nil
playing[pname].timer = 0
else
ok = false -- sound set still playing, skip new sound
end
end
-- set random chance
chance = random(1000)
-- if chance is lower than set frequency then select set
if ok and set_name and chance < sound_sets[set_name].frequency then
number = random(#sound_sets[set_name].sounds) -- choose random sound from set
ambience = sound_sets[set_name].sounds[number] -- grab sound information
-- play sound
handler = minetest.sound_play(ambience.name, {
to_player = pname,
gain = ((ambience.gain or 0.3) + (MORE_GAIN or 0)) * playing[pname].svol,
pitch = ambience.pitch or 1.0
}, ambience.ephemeral)
--print ("playing... " .. ambience.name .. " (" .. chance .. " < "
-- .. sound_sets[set_name].frequency .. ") @ ", MORE_GAIN, handler)
if handler then
-- set what player is currently listening to if handler found
playing[pname].set = set_name
playing[pname].gain = MORE_GAIN
playing[pname].handler = handler
playing[pname].timer = ambience.length
end
end
end
end)
-- sound volume command
minetest.register_chatcommand("svol", {
params = S("<svol>"),
description = S("set sound volume (0.1 to 1.0)"),
privs = {},
func = function(name, param)
local svol = tonumber(param) or playing[name].svol
if svol < 0.1 then svol = 0.1 end
if svol > 1.0 then svol = 1.0 end
local player = minetest.get_player_by_name(name)
local meta = player:get_meta()
meta:set_string("ambience.svol", svol)
playing[name].svol = svol
return true, S("Sound volume set to @1", svol)
end
})
-- music volume command (0 stops music)
minetest.register_chatcommand("mvol", {
params = S("<mvol>"),
description = S("set music volume (0.1 to 1.0, 0 to stop music)"),
privs = {},
func = function(name, param)
local mvol = tonumber(param) or playing[name].mvol
-- stop music currently playing by setting volume to 0
if mvol == 0 and playing[name].music_handler then
minetest.sound_stop(playing[name].music_handler)
playing[name].music_handler = nil
minetest.chat_send_player(name, S("Music stopped!"))
end
if mvol < 0 then mvol = 0 end
if mvol > 1.0 then mvol = 1.0 end
local player = minetest.get_player_by_name(name)
local meta = player:get_meta()
meta:set_string("ambience.mvol", mvol)
playing[name].mvol = mvol
return true, S("Music volume set to @1", mvol)
end
})
-- load default sound sets
dofile(minetest.get_modpath("ambience") .. "/soundsets.lua")
print("[MOD] Ambience Lite loaded")