utility.lua 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. -- This file is reloadable.
  2. -- Localize vector.distance() for performance.
  3. local vector_distance = vector.distance
  4. -- Checks if the given position would place the player underwater, swimming, or not-in-water.
  5. ambiance.check_underwater = function(pos)
  6. local registered = minetest.reg_ns_nodes
  7. local n2 = minetest.get_node({x=pos.x, y=pos.y+0.2, z=pos.z}).name
  8. local nf = registered[n2]
  9. if nf and nf.groups and nf.groups.water then
  10. local n1 = minetest.get_node({x=pos.x, y=pos.y+1.4, z=pos.z}).name
  11. local nh = registered[n1]
  12. if nh and nh.groups and nh.groups.water then
  13. return 2 -- Feet and head submerged.
  14. end
  15. return 1 -- Feet submerged.
  16. end
  17. return 0 -- Not in water.
  18. end
  19. -- Checks given time against the named time, returning success if the time matches.
  20. ambiance.check_time = function(timename, curtime)
  21. if timename == "" then
  22. return true
  23. end
  24. local goodtime = false
  25. local curtime = minetest.get_timeofday()
  26. if curtime then
  27. if timename == "night" and (curtime < 0.2 or curtime > 0.8) then
  28. goodtime = true
  29. elseif timename == "day" and (curtime > 0.3 and curtime < 0.7) then
  30. goodtime = true
  31. elseif timename == "noon" and (curtime > 0.4 and curtime < 0.6) then
  32. goodtime = true
  33. elseif timename == "midnight" and (curtime > 0.9 or curtime < 0.1) then
  34. goodtime = true
  35. elseif timename == "dusk" and (curtime > 0.7 and curtime < 0.8) then
  36. goodtime = true
  37. elseif timename == "dawn" and (curtime > 0.2 and curtime < 0.3) then
  38. goodtime = true
  39. elseif timename == "liminal" and ((curtime > 0.2 and curtime < 0.3) or (curtime > 0.7 and curtime < 0.8)) then
  40. goodtime = true
  41. end
  42. end
  43. return goodtime
  44. end
  45. local compute_gain = function(distance, max)
  46. assert(max >= 1)
  47. local res = (100.0 * distance) / max
  48. res = res / 100.0
  49. if res < 0 then res = 0 end
  50. if res > 1 then res = 1 end
  51. res = (res * -1) + 1
  52. return res
  53. end
  54. ambiance.compute_gain = compute_gain
  55. -- This function plays a sound for each player within a given range.
  56. -- The audio gain is reduced for players far from the position at which the sound should play.
  57. ambiance.sound_play = function(name, pos, gain, range, exempt_player, ephemeral)
  58. -- Range check! Stupid engine bug. >:(
  59. if pos.x > 31000 or pos.x < -31000 or pos.z > 31000 or pos.z < -31000 or pos.y > 31000 or pos.y < -31000 then
  60. return -- Abort!
  61. end
  62. local eph = true
  63. if ephemeral ~= nil then
  64. eph = ephemeral
  65. end
  66. local exempt = exempt_player or ""
  67. local players = minetest.get_objects_inside_radius(pos, range)
  68. for k, v in ipairs(players) do
  69. if v:is_player() then
  70. local n = v:get_player_name()
  71. if n ~= exempt then
  72. local p1 = v:getpos()
  73. local dist = vector_distance(p1, pos)
  74. local gn = compute_gain(dist, range)
  75. -- Ephemeral sound.
  76. minetest.sound_play(name, {to_player=n, gain=gn*gain}, eph)
  77. end
  78. end
  79. end
  80. end
  81. -- Check if the given position is in-doors, or out in the open.
  82. ambiance.check_indoors = function(pname, pos)
  83. -- Check for sunlight if on the surface. This is a fast, quick hack that works.
  84. if pos.y > -20 then
  85. -- Is position indoors?
  86. -- The brightest lamp gives light-level 13 on its 8 adjacent nodes.
  87. -- This means light-level 14 and 15 represent sunlight.
  88. if (minetest.get_node_light(vector.add(pos, {x=0, y=1, z=0}), 0.5) or 0) < 14 then
  89. return true
  90. end
  91. else
  92. -- Player is underground. In this case, 'indoors' can be taken to mean 'inside a developed area'.
  93. -- Undeveloped areas will be made out of stone.
  94. -- So we can check what material the player is standing on, this will work most of the time.
  95. local nodename = sky.get_last_walked_node(pname)
  96. -- Capture stone.
  97. if nodename == "default:stone" or string.find(nodename, "stone_with") then
  98. return false
  99. end
  100. -- Capture (non-default) ores in stone, and anything cobble (including stairs).
  101. if string.find(nodename, "cobble") or string.find(nodename, "[_:]ore") or string.find(nodename, "mineral") then
  102. return false
  103. end
  104. -- Capture anything in the 'rackstone' group. This group should not be used for materials a player might build a house out of.
  105. if minetest.get_item_group(nodename, "rackstone") ~= 0 then
  106. return false
  107. end
  108. -- Player is underground, but standing on something manmade, therefore not 'out-doors'.
  109. return true
  110. end
  111. return false
  112. end