init.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. sky = sky or {}
  2. sky.modpath = minetest.get_modpath("sky")
  3. sky.players = sky.players or {}
  4. -- Localize for speed.
  5. local get_node = minetest.get_node
  6. local all_nodes = minetest.registered_nodes
  7. local ns_nodes = minetest.reg_ns_nodes
  8. local vector_distance = vector.distance
  9. local vector_round = vector.round
  10. local vector_equals = vector.equals
  11. local get_connected_players = minetest.get_connected_players
  12. local random = math.random
  13. local string_find = string.find
  14. -- Public API function.
  15. -- Used in the ambiance mod to determine the surface a player stands on.
  16. function sky.get_last_walked_node(pname)
  17. local data = sky.players[pname]
  18. if data then
  19. return data.snode
  20. end
  21. return ""
  22. end
  23. function sky.get_last_walked_nodeabove(pname)
  24. local data = sky.players[pname]
  25. if data then
  26. return data.wnode
  27. end
  28. return ""
  29. end
  30. -- Private function!
  31. -- This is the default `on_walkover' action.
  32. local function default_on_walkover(pos, name, player)
  33. local pname = player:get_player_name()
  34. -- Admin doesn't trigger default actions.
  35. if gdac.player_is_admin(pname) then
  36. return
  37. end
  38. -- Do not trigger if position is protected.
  39. if minetest.test_protection(pos, "") then
  40. return
  41. end
  42. if get_node(pos).name ~= name then
  43. return
  44. end
  45. local test_and_drop = function(p2)
  46. -- Don't drop if protected.
  47. if minetest.test_protection(p2, "") then
  48. return
  49. end
  50. local overhang = true
  51. for i = 1, 4, 1 do
  52. local node = get_node({x=p2.x, y=p2.y-i, z=p2.z})
  53. if node.name ~= "air" then
  54. overhang = false
  55. break
  56. end
  57. end
  58. if overhang then
  59. sfn.drop_node(p2)
  60. core.check_for_falling(p2)
  61. return true
  62. end
  63. end
  64. -- Drop several nodes under the player to ensure a likelihood of
  65. -- causing the player to fall down.
  66. local positions = {
  67. -- Test and drop lower nodes first.
  68. {x=pos.x, y=pos.y-1, z=pos.z},
  69. {x=pos.x+1, y=pos.y-1, z=pos.z},
  70. {x=pos.x-1, y=pos.y-1, z=pos.z},
  71. {x=pos.x, y=pos.y-1, z=pos.z+1},
  72. {x=pos.x, y=pos.y-1, z=pos.z-1},
  73. {x=pos.x, y=pos.y, z=pos.z},
  74. {x=pos.x+1, y=pos.y, z=pos.z},
  75. {x=pos.x-1, y=pos.y, z=pos.z},
  76. {x=pos.x, y=pos.y, z=pos.z+1},
  77. {x=pos.x, y=pos.y, z=pos.z-1},
  78. }
  79. local play_sound = false
  80. for k, v in ipairs(positions) do
  81. if test_and_drop(v) then
  82. play_sound = true
  83. end
  84. end
  85. if play_sound then
  86. ambiance.sound_play("default_gravel_footstep", pos, 1, 20)
  87. end
  88. end
  89. -- Private function!
  90. --
  91. -- This handles skycolor updates and `on_player_walk_over' calls.
  92. -- The walk-over calls are used in plenty of places, so do not break this!
  93. -- Also, we handle movement speed based on current node walked on.
  94. local function update_player(player, pname, pdata, playerpos, nodepos)
  95. -- Player doesn't walk over nodes if attached to some vehicle.
  96. if not default.player_attached[pname] then
  97. -- Get node player is standing ON.
  98. local snode = get_node(nodepos)
  99. local sname = snode.name
  100. -- Don't modify movement or call walk-over callbacks if node is air.
  101. -- This prevents players from getting better movement speed by hopping constantly.
  102. if sname ~= "air" and sname ~= "ignore" then
  103. local sdef = ns_nodes[sname] or all_nodes[sname] or {}
  104. -- Get node player is walking IN, not ON.
  105. -- Plants shall slow players down!
  106. local wnode = get_node(vector.add(nodepos, {x=0, y=1, z=0}))
  107. local wname = wnode.name
  108. -- Recompute movement speed only if either walked nodename changes.
  109. if sname ~= pdata.snode or wname ~= pdata.wnode then
  110. if sdef.movement_speed_depends then
  111. -- Assume node is slab-like and has a standard 'flat' orientation.
  112. local p2 = snode.param2
  113. local is_flat = false
  114. if p2 >= 0 and p2 <= 3 then
  115. is_flat = true
  116. elseif p2 >= 20 and p2 <= 23 then
  117. is_flat = true
  118. end
  119. if is_flat then
  120. -- If slab is flat and has a parent type, use the parent type.
  121. local def2 = ns_nodes[sdef.movement_speed_depends] or {}
  122. if def2 then sdef = def2 end
  123. end
  124. elseif sdef.move_speed_stair then
  125. -- Assume node is stair-like and has a standard 'flat' orientation.
  126. local p2 = snode.param2
  127. local is_flat = false
  128. if p2 >= 20 and p2 <= 23 then
  129. is_flat = true
  130. end
  131. if is_flat then
  132. -- If stair is flat and has a parent type, use the parent type.
  133. local def2 = ns_nodes[sdef.move_speed_stair] or {}
  134. if def2 then sdef = def2 end
  135. end
  136. end
  137. local smult = sdef.movement_speed_multiplier or default.NORM_SPEED
  138. local jmult = sdef.movement_jump_multiplier or default.NORM_JUMP
  139. sprint.set_speed_multiplier(pname, smult)
  140. sprint.set_jump_multiplier(pname, jmult)
  141. if wname ~= "air" then
  142. -- But ignore doors.
  143. if not string.find(wname, "^doors:") then
  144. local wdef = ns_nodes[wname] or all_nodes[wname] or {}
  145. local smult2 = wdef.movement_speed_multiplier or default.NORM_SPEED
  146. local jmult2 = wdef.movement_jump_multiplier or default.NORM_JUMP
  147. sprint.set_speed_multiplier(pname, smult2)
  148. sprint.set_jump_multiplier(pname, jmult2)
  149. end
  150. end
  151. -- Record the name of the last walked node.
  152. -- This is used by the ambiance mod to determine walked surface type.
  153. pdata.snode = sname
  154. pdata.wnode = wname
  155. end
  156. -- Execute `on_walkover' callback for current walked node.
  157. -- Note, this must only be called ONCE for the walked node!
  158. -- This is ensured because we are only called max once per position.
  159. if sdef.walkable and sdef.on_player_walk_over then
  160. sdef.on_player_walk_over(nodepos, player)
  161. end
  162. -- The default action is only rarely taken.
  163. if not sdef._no_collapse_on_walkover then
  164. if random(1, 500) == 1 then
  165. default_on_walkover(nodepos, sname, player)
  166. end
  167. end
  168. end -- Air/ignore check.
  169. end
  170. -- Update player's sky colors. Use flags to avoid extra calls.
  171. if vector_distance(playerpos, pdata.ppos) > 5 or pdata.sky == -1 then
  172. if rc.position_underground(playerpos) and pdata.sky <= 0 then
  173. if playerpos.y > -25000 and pdata.sky ~= 1 then
  174. -- Cave (natural) background.
  175. player:set_sky({base_color={a=255, r=0, g=0, b=0}, type="plain", clouds=false})
  176. player:set_sun({visible=false, sunrise_visible=false})
  177. player:set_moon({visible=false})
  178. player:set_stars({visible=false})
  179. pdata.sky = 1
  180. elseif pdata.sky ~= 2 then
  181. -- Nether (cave) background.
  182. player:set_sky({base_color={a=255, r=10, g=0, b=0}, type="plain", clouds=false})
  183. player:set_sun({visible=false, sunrise_visible=false})
  184. player:set_moon({visible=false})
  185. player:set_stars({visible=false})
  186. pdata.sky = 2
  187. end
  188. elseif not rc.position_underground(playerpos) and pdata.sky ~= 0 then
  189. player:set_sky(rc.get_realm_sky(playerpos))
  190. player:set_sun(rc.get_realm_sun(playerpos))
  191. player:set_moon(rc.get_realm_moon(playerpos))
  192. player:set_stars(rc.get_realm_stars(playerpos))
  193. player:set_clouds(rc.get_realm_clouds(playerpos))
  194. pdata.sky = 0
  195. end
  196. pdata.ppos = playerpos
  197. end
  198. end
  199. -- Private function! (Registered callback.)
  200. local timer = 0
  201. function sky.on_globalstep(dtime)
  202. timer = timer + dtime
  203. if timer < 0.25 then return end
  204. timer = 0
  205. local players = get_connected_players()
  206. local datas = sky.players
  207. for i=1, #players do
  208. local player = players[i]
  209. local pname = player:get_player_name()
  210. local ppos = player:get_pos()
  211. local rpos = vector_round(ppos)
  212. local pdata = datas[pname]
  213. if not vector_equals(pdata.rpos, rpos) then
  214. local npos = utility.node_under_pos(ppos)
  215. update_player(player, pname, pdata, ppos, npos)
  216. pdata.rpos = rpos
  217. end
  218. end
  219. end
  220. function sky.on_joinplayer(player)
  221. local ppos = player:get_pos()
  222. local rpos = vector_round(ppos)
  223. local npos = utility.node_under_pos(ppos)
  224. -- Initialize player data.
  225. local pname = player:get_player_name()
  226. sky.players[pname] = {
  227. ppos = {x=0, y=0, z=0}, -- Last known player position.
  228. rpos = rpos, -- Last known player position, rounded.
  229. snode = "", -- Name of last walked node.
  230. wnode = "", -- Name of last node above walked node.
  231. sky = -1, -- Current sky colors flag.
  232. }
  233. local pdata = sky.players[pname]
  234. -- Update player on first join.
  235. update_player(player, pname, pdata, ppos, npos)
  236. end
  237. function sky.on_leaveplayer(player, timeout)
  238. local pname = player:get_player_name()
  239. sky.players[pname] = nil
  240. end
  241. function sky.notify_sky_update_needed(pname)
  242. -- "-1" indicates that the sky needs updating for this player.
  243. sky.players[pname].sky = -1
  244. end
  245. if not sky.run_once then
  246. minetest.register_on_joinplayer(function(...)
  247. sky.on_joinplayer(...)
  248. end)
  249. minetest.register_on_leaveplayer(function(...)
  250. return sky.on_leaveplayer(...)
  251. end)
  252. minetest.register_globalstep(function(...)
  253. sky.on_globalstep(...)
  254. end)
  255. local c = "sky:core"
  256. local f = sky.modpath .. "/init.lua"
  257. reload.register_file(c, f, false)
  258. sky.run_once = true
  259. end