treesounds.lua 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. -- Localize vector.distance() for performance.
  2. local vector_distance = vector.distance
  3. local math_random = math.random
  4. ambiance.tree_sounds = {
  5. {name="craw", gain=1.0, miny=-20, maxy=500, time="day" , indoors=false, mintime=120, maxtime=360, },
  6. {name="hornedowl", gain=1.0, miny=-20, maxy=500, time="night", indoors=false, mintime=120, maxtime=360, },
  7. -- More animal sounds. These should play with less frequency.
  8. {name="cricket", gain=1.0, miny=-20, maxy=500, time="night", indoors=false, },
  9. {name="jungle_night_1", gain=1.0, miny=-20, maxy=500, time="night", indoors=false, },
  10. {name="cardinal", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, mintime=20, maxtime=60, },
  11. {name="crestedlark", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, mintime=20, maxtime=60, },
  12. {name="deer", gain=1.0, miny=-20, maxy=500, time="night", indoors=false, mintime=20, maxtime=120, },
  13. {name="frog", gain=0.7, miny=-20, maxy=500, time="liminal", indoors=false, },
  14. {name="robin", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, },
  15. {name="bluejay", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, },
  16. {name="gull", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, },
  17. {name="peacock", gain=1.0, miny=-20, maxy=500, time="liminal", indoors=false, },
  18. {name="canadianloon1", gain=1.0, miny=-20, maxy=500, time="night", indoors=false, mintime=120, maxtime=360, },
  19. }
  20. -- Initialize extra table parameters.
  21. for k, v in ipairs(ambiance.tree_sounds) do
  22. -- Mintime & maxtime are the min and max seconds a sound can play again after it has played.
  23. -- The timer is reset to a new random value between min and max every time the sound plays.
  24. v.mintime = v.mintime or 30
  25. v.maxtime = v.maxtime or 120
  26. if v.mintime < 0 then v.mintime = 0 end
  27. if v.maxtime < v.mintime then v.maxtime = v.mintime end
  28. -- If minimum or maximum gain are not specified, calculate min and max gain.
  29. v.mingain = v.mingain or (v.gain - 0.5)
  30. v.maxgain = v.maxgain or (v.gain + 0.1)
  31. if v.mingain < 0 then v.mingain = 0 end
  32. if v.maxgain < v.mingain then v.maxgain = v.mingain end
  33. -- Initialize timer to a random value between min and max time.
  34. -- This ensures all sounds start with random times on first run.
  35. v.timer = math_random(v.mintime, v.maxtime)
  36. v.range = v.range or 30
  37. end
  38. if not ambiance.tree_sounds_registered then
  39. ambiance.register_sound_beacon(":soundbeacon:trees", {
  40. -- Minimum and maximum times between environment checks.
  41. check_time_min = 60,
  42. check_time_max = 60*60,
  43. -- Minimum and maximum times between sounds playing.
  44. play_time_min = 5,
  45. play_time_max = 30,
  46. -- Shall check the beacon's nearby environment, and return 'true' if beacon
  47. -- can remain, 'false' or 'nil' if it should be removed. Data can be stored in
  48. -- `data`. `pos` is always a rounded position.
  49. on_check_environment = function(data, pos)
  50. local p1 = vector.add(pos, {x=-3, y=-3, z=-3})
  51. local p2 = vector.add(pos, {x=3, y=3, z=3})
  52. local nodes = {"group:leaves", "group:tree"}
  53. local positions = minetest.find_nodes_in_area(p1, p2, nodes)
  54. if #positions > 10 then
  55. return true
  56. end
  57. --minetest.chat_send_all("removed!")
  58. end,
  59. -- Shall play sound to nearby players (or check whether sound can be played at
  60. -- this time). Data can be stored in `data`. `pos` is
  61. -- always a rounded position. `dtime` is seconds since last call to func.
  62. on_play_sound = function(data, pos, dtime)
  63. if not data.sounds then
  64. data.sounds = table.copy(ambiance.tree_sounds)
  65. end
  66. -- For all sounds, check if anyone can hear them. If yes, play sound to players that can hear.
  67. local allsounds = data.sounds or {}
  68. --minetest.chat_send_all("num: " .. #allsounds)
  69. -- Get current time of day.
  70. local curtime = minetest.get_timeofday()
  71. local rand = math_random
  72. for k, v in ipairs(allsounds) do
  73. v.timer = v.timer - dtime
  74. if v.timer <= 0 then
  75. -- Timer has expired, fire sound (if possible).
  76. -- Also reset the timer so the sound can fire again.
  77. v.timer = rand(v.mintime, v.maxtime)
  78. -- Can this sound play at the current time of day?
  79. if ambiance.check_time(v.time, curtime) then
  80. -- Scan through all players. The following checks must be done per-player.
  81. local players = minetest.get_connected_players()
  82. for _, pref in ipairs(players) do
  83. local pname = pref:get_player_name()
  84. local ppos = utility.get_foot_pos(pref:get_pos())
  85. --minetest.chat_send_all("found player")
  86. -- Is player in this sounds's Y layer?
  87. if ppos.y >= v.miny and ppos.y <= v.maxy then
  88. local pdist = vector_distance(pos, ppos)
  89. if pdist < v.range then
  90. -- Don't play sound if player is underwater (muted sounds).
  91. -- Note: player's underwater status is modified by the scuba code.
  92. local underwater = ambiance.players[pname].underwater
  93. if underwater == nil then
  94. -- Only play sound if sound can be played indoors or out-of-doors.
  95. -- If sound doesn't care whether indoors or out-of-doors, then play it.
  96. local indoors
  97. if v.indoors ~= nil then
  98. -- Randomize position a bit in case player is just standing under an overhang.
  99. ppos.x = rand(ppos.x - 1, ppos.x + 1)
  100. ppos.y = rand(ppos.y - 1, ppos.y + 1)
  101. ppos.z = rand(ppos.z - 1, ppos.z + 1)
  102. indoors = ambiance.check_indoors(pname, ppos)
  103. end
  104. if v.indoors == indoors then
  105. -- Play sound to current player!
  106. -- If multiple players can hear, the sound will be played at the same time to all of them.
  107. local gain = rand(v.mingain*100.0, v.maxgain*100.0)/100.0
  108. -- Clamp gain!
  109. if gain < 0.0 then gain = 0.0 end
  110. if gain > 2.0 then gain = 2.0 end
  111. local md = ambiance.compute_gain(pdist, v.range)
  112. minetest.sound_play(v.name, {to_player=pname, gain=gain*md}, true)
  113. end
  114. end
  115. end
  116. end
  117. end
  118. end
  119. end
  120. end
  121. end,
  122. })
  123. ambiance.tree_sounds_registered = true
  124. end