beacon.lua 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. -- Localize for performance.
  2. local vector_round = vector.round
  3. -- Spawn a named sound beacon at `pos`, while ensuring that no more than `count`
  4. -- beacons of the same type are spawned within `radius` meters.
  5. function ambiance.spawn_sound_beacon(name, pos, radius, count)
  6. radius = radius or 0.5
  7. count = count or 1
  8. pos = vector_round(pos)
  9. local objs = minetest.get_objects_inside_radius(pos, radius)
  10. local c = 0
  11. for i = 1, #objs, 1 do
  12. local ent = objs[i]:get_luaentity()
  13. if ent then
  14. if ent.name == name then
  15. c = c + 1
  16. if c > count then
  17. -- Too many sound beacons of this type in the region.
  18. return
  19. end
  20. end
  21. end
  22. end
  23. --minetest.chat_send_all("added " .. name .. "!")
  24. local ent = minetest.add_entity(pos, name)
  25. if ent then
  26. local lent = ent:get_luaentity()
  27. if not lent then
  28. ent:remove()
  29. return
  30. end
  31. -- Set initial check/play times to zero,
  32. -- this makes sound play instantly on first spawn.
  33. if lent._play_immediate then
  34. lent._ctime = 0
  35. lent._ptime = 0
  36. end
  37. end
  38. end
  39. -- Trigger all sound beacons in a given radius to execute an environment recheck.
  40. function ambiance.recheck_nearby_sound_beacons(pos, radius)
  41. --minetest.chat_send_all('recheck2')
  42. pos = vector_round(pos)
  43. local objs = minetest.get_objects_inside_radius(pos, radius)
  44. for i = 1, #objs, 1 do
  45. local ent = objs[i]:get_luaentity()
  46. if ent then
  47. if ent.name:find("^soundbeacon:") then
  48. --minetest.chat_send_all('recheck')
  49. ent._ctime = 0
  50. end
  51. end
  52. end
  53. end
  54. function ambiance.replay_nearby_sound_beacons(pos, radius)
  55. --minetest.chat_send_all('replay2')
  56. pos = vector_round(pos)
  57. local objs = minetest.get_objects_inside_radius(pos, radius)
  58. for i = 1, #objs, 1 do
  59. local ent = objs[i]:get_luaentity()
  60. if ent then
  61. if ent.name:find("^soundbeacon:") then
  62. --minetest.chat_send_all('replay')
  63. ent._ptime = 0
  64. end
  65. end
  66. end
  67. end
  68. function ambiance.spawn_sound_beacon_inside_area(name, pos, minp, maxp, radius, count)
  69. local p1 = vector.add(pos, minp)
  70. local p2 = vector.add(pos, maxp)
  71. local p3 = {x=0, y=0, z=0}
  72. p3.x = p1.x + p2.x / 2
  73. p3.y = p1.y + p2.y / 2
  74. p3.z = p1.z + p2.z / 2
  75. ambiance.spawn_sound_beacon(name, pos, radius, count)
  76. end
  77. function ambiance.register_sound_beacon(name, callbacks)
  78. local cmin = callbacks.check_time_min or callbacks.check_time
  79. local cmax = callbacks.check_time_max or callbacks.check_time
  80. local pmin = callbacks.play_time_min or callbacks.play_time
  81. local pmax = callbacks.play_time_max or callbacks.play_time
  82. local check = callbacks.on_check_environment
  83. local play = callbacks.on_play_sound
  84. local stop = callbacks.on_stop_sound
  85. local rand = math.random
  86. local beacondef = {
  87. visual = "wielditem",
  88. visual_size = {x=0, y=0},
  89. collisionbox = {0, 0, 0, 0, 0, 0},
  90. physical = false,
  91. textures = {"air"},
  92. is_visible = false,
  93. _play_immediate = callbacks.play_immediate,
  94. on_activate = function(self, staticdata, dtime_s)
  95. if self._play_immediate then
  96. self._ptime = 0
  97. self._ctime = 0
  98. end
  99. end,
  100. on_punch = function(self, puncher, time_from_last_punch, tool_caps, dir)
  101. end,
  102. on_death = function(self, killer)
  103. end,
  104. on_rightclick = function(self, clicker)
  105. end,
  106. get_staticdata = function(self)
  107. return ""
  108. end,
  109. on_step = function(self, dtime)
  110. local pos = vector_round(self.object:get_pos())
  111. self._data = self._data or {}
  112. local d = self._data
  113. self._ctime = (self._ctime or rand(cmin, cmax)) - dtime
  114. self._ptime = (self._ptime or rand(pmin, pmax)) - dtime
  115. self._xtime = (self._xtime or 0) + dtime
  116. if self._ctime < 0 then
  117. self._ctime = rand(cmin, cmax)
  118. if not check(d, pos) then
  119. if stop then
  120. stop(d)
  121. end
  122. self.object:remove()
  123. return
  124. end
  125. end
  126. if self._ptime < 0 then
  127. self._ptime = rand(pmin, pmax)
  128. play(d, pos, self._xtime)
  129. self._xtime = 0
  130. end
  131. end,
  132. }
  133. minetest.register_entity(name, beacondef)
  134. end