Replace getpos() with get_pos()
[MineClone/MineClone2.git] / mods / ENVIRONMENT / mcl_weather / rain.lua
blob8a4cff0870375eed85dbed0fb7426f6cd7979af6
1 local PARTICLES_COUNT_RAIN = 30
2 local PARTICLES_COUNT_THUNDER = 45
4 mcl_weather.rain = {
5 -- max rain particles created at time
6 particles_count = PARTICLES_COUNT_RAIN,
8 -- flag to turn on/off extinguish fire for rain
9 extinguish_fire = true,
11 -- flag useful when mixing weathers
12 raining = false,
14 -- keeping last timeofday value (rounded).
15 -- Defaulted to non-existing value for initial comparing.
16 sky_last_update = -1,
18 init_done = false,
21 mcl_weather.rain.sound_handler = function(player)
22 return minetest.sound_play("weather_rain", {
23 to_player = player,
24 loop = true,
26 end
28 -- set skybox based on time (uses skycolor api)
29 mcl_weather.rain.set_sky_box = function()
30 if mcl_weather.state == "rain" then
31 mcl_weather.skycolor.add_layer(
32 "weather-pack-rain-sky",
33 {{r=0, g=0, b=0},
34 {r=85, g=86, b=98},
35 {r=135, g=135, b=151},
36 {r=85, g=86, b=98},
37 {r=0, g=0, b=0}})
38 mcl_weather.skycolor.active = true
39 for _, player in pairs(minetest.get_connected_players()) do
40 player:set_clouds({color="#5D5D5FE8"})
41 end
42 end
43 end
45 -- creating manually parctiles instead of particles spawner because of easier to control
46 -- spawn position.
47 mcl_weather.rain.add_rain_particles = function(player)
49 mcl_weather.rain.last_rp_count = 0
50 for i=mcl_weather.rain.particles_count, 1,-1 do
51 local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
52 if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then
53 mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
54 minetest.add_particle({
55 pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
56 velocity = {x=0, y=-10, z=0},
57 acceleration = {x=0, y=-30, z=0},
58 expirationtime = 0.2,
59 size = math.random(0.5, 3),
60 collisiondetection = true,
61 collision_removal = true,
62 vertical = true,
63 texture = mcl_weather.rain.get_texture(),
64 playername = player:get_player_name()
66 end
67 end
68 end
70 -- Simple random texture getter
71 mcl_weather.rain.get_texture = function()
72 local texture_name
73 local random_number = math.random()
74 if random_number > 0.33 then
75 texture_name = "weather_pack_rain_raindrop_1.png"
76 elseif random_number > 0.66 then
77 texture_name = "weather_pack_rain_raindrop_2.png"
78 else
79 texture_name = "weather_pack_rain_raindrop_3.png"
80 end
81 return texture_name;
82 end
84 -- register player for rain weather.
85 -- basically needs for origin sky reference and rain sound controls.
86 mcl_weather.rain.add_player = function(player)
87 if mcl_weather.players[player:get_player_name()] == nil then
88 local player_meta = {}
89 player_meta.origin_sky = {player:get_sky()}
90 mcl_weather.players[player:get_player_name()] = player_meta
91 end
92 end
94 -- remove player from player list effected by rain.
95 -- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
96 mcl_weather.rain.remove_player = function(player)
97 local player_meta = mcl_weather.players[player:get_player_name()]
98 if player_meta ~= nil and player_meta.origin_sky ~= nil then
99 player:set_sky(player_meta.origin_sky[1], player_meta.origin_sky[2], player_meta.origin_sky[3], true)
100 player:set_clouds({color="#FFF0F0E5"})
101 mcl_weather.players[player:get_player_name()] = nil
105 mcl_worlds.register_on_dimension_change(function(player, dimension)
106 if dimension ~= "overworld" and dimension ~= "void" then
107 mcl_weather.rain.remove_sound(player)
108 mcl_weather.rain.remove_player(player)
109 elseif dimension == "overworld" then
110 mcl_weather.rain.update_sound(player)
111 if mcl_weather.rain.raining then
112 mcl_weather.rain.add_rain_particles(player)
113 mcl_weather.rain.add_player(player)
116 end)
118 -- adds and removes rain sound depending how much rain particles around player currently exist.
119 -- have few seconds delay before each check to avoid on/off sound too often
120 -- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
121 mcl_weather.rain.update_sound = function(player)
122 local player_meta = mcl_weather.players[player:get_player_name()]
123 if player_meta ~= nil then
124 if player_meta.sound_updated ~= nil and player_meta.sound_updated + 5 > minetest.get_gametime() then
125 return false
128 if player_meta.sound_handler ~= nil then
129 if mcl_weather.rain.last_rp_count == 0 then
130 minetest.sound_stop(player_meta.sound_handler)
131 player_meta.sound_handler = nil
133 elseif mcl_weather.rain.last_rp_count > 0 then
134 player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
137 player_meta.sound_updated = minetest.get_gametime()
141 -- rain sound removed from player.
142 mcl_weather.rain.remove_sound = function(player)
143 local player_meta = mcl_weather.players[player:get_player_name()]
144 if player_meta ~= nil and player_meta.sound_handler ~= nil then
145 minetest.sound_stop(player_meta.sound_handler)
146 player_meta.sound_handler = nil
147 player_meta.sound_updated = nil
151 -- callback function for removing rain
152 mcl_weather.rain.clear = function()
153 mcl_weather.rain.raining = false
154 mcl_weather.rain.sky_last_update = -1
155 mcl_weather.rain.init_done = false
156 mcl_weather.rain.set_particles_mode("rain")
157 mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
158 for _, player in ipairs(minetest.get_connected_players()) do
159 mcl_weather.rain.remove_sound(player)
160 mcl_weather.rain.remove_player(player)
164 minetest.register_globalstep(function(dtime)
165 if mcl_weather.state ~= "rain" then
166 return false
169 mcl_weather.rain.make_weather()
170 end)
172 mcl_weather.rain.make_weather = function()
173 if mcl_weather.rain.init_done == false then
174 mcl_weather.rain.raining = true
175 mcl_weather.rain.set_sky_box()
176 mcl_weather.rain.set_particles_mode(mcl_weather.mode)
177 mcl_weather.rain.init_done = true
180 for _, player in ipairs(minetest.get_connected_players()) do
181 if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
182 mcl_weather.rain.remove_sound(player)
183 return false
185 mcl_weather.rain.add_player(player)
186 mcl_weather.rain.add_rain_particles(player)
187 mcl_weather.rain.update_sound(player)
191 -- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
192 mcl_weather.rain.set_particles_mode = function(mode)
193 if mode == "thunder" then
194 mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
195 else
196 mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
200 if mcl_weather.allow_abm then
201 -- ABM for extinguish fire
202 minetest.register_abm({
203 label = "Rain extinguishes fire",
204 nodenames = {"mcl_fire:fire"},
205 interval = 2.0,
206 chance = 2,
207 action = function(pos, node, active_object_count, active_object_count_wider)
208 if mcl_weather.rain.raining and mcl_weather.rain.extinguish_fire then
209 if mcl_weather.is_outdoor(pos) then
210 minetest.remove_node(pos)
211 minetest.sound_play("fire_extinguish_flame", {pos = pos, max_hear_distance = 8, gain = 0.1})
214 end,
217 -- Slowly fill up cauldrons
218 minetest.register_abm({
219 label = "Rain fills cauldrons with water",
220 nodenames = {"mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1", "mcl_cauldrons:cauldron_2"},
221 interval = 56.0,
222 chance = 1,
223 action = function(pos, node, active_object_count, active_object_count_wider)
224 -- Rain is equivalent to a water bottle
225 if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
226 if node.name == "mcl_cauldrons:cauldron" then
227 minetest.set_node(pos, {name="mcl_cauldrons:cauldron_1"})
228 elseif node.name == "mcl_cauldrons:cauldron_1" then
229 minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2"})
230 elseif node.name == "mcl_cauldrons:cauldron_2" then
231 minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
232 elseif node.name == "mcl_cauldrons:cauldron_1r" then
233 minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2r"})
234 elseif node.name == "mcl_cauldrons:cauldron_2r" then
235 minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
241 -- Wetten the soil
242 minetest.register_abm({
243 label = "Rain hydrates farmland",
244 nodenames = {"mcl_farming:soil"},
245 interval = 22.0,
246 chance = 3,
247 action = function(pos, node, active_object_count, active_object_count_wider)
248 if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
249 if node.name == "mcl_farming:soil" then
250 minetest.set_node(pos, {name="mcl_farming:soil_wet"})
257 if mcl_weather.reg_weathers.rain == nil then
258 mcl_weather.reg_weathers.rain = {
259 clear = mcl_weather.rain.clear,
260 light_factor = 0.6,
261 -- 10min - 20min
262 min_duration = 600,
263 max_duration = 1200,
264 transitions = {
265 [65] = "none",
266 [70] = "snow",
267 [100] = "thunder",