utility.lua 4.2 KB

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