]> git.lizzy.rs Git - crafter_client.git/blob - weather_handling.lua
Update README.md
[crafter_client.git] / weather_handling.lua
1 local
2 minetest,name,vector,math,pairs
3 =
4 minetest,minetest.localplayer:get_name(),vector,math,pairs
5
6 local weather_intake = minetest.mod_channel_join("weather_intake")
7 local weather = minetest.mod_channel_join("weather_nodes")
8 local weather_type = minetest.mod_channel_join("weather_type")
9
10 local all_nodes = {}
11 local do_effects = false
12 local snow = false
13 local rain = false
14 local weather_update_timer = 0
15 local id_table = {}
16
17 local rain_sound_handle = nil
18
19 local liquids = {
20         ["main:water"] = true,
21         ["main:waterflow"] = true,
22         ["main:lava"] = true,
23         ["main:lavaflow"] = true,
24         ["nether:lava"] = true,
25         ["nether:lavaflow"] = true,
26 }
27
28
29 local y
30 local pos
31 local radius = 10
32 local particle_table
33 local area
34 local min
35 local max
36 local area_index
37 local spawn_table
38 local lightlevel
39 local null
40 local curr_light
41 local distance = vector.distance
42 local current_node 
43 local weather_effects = function(player,defined_type)
44         pos = vector.round(player:get_pos())
45         area = vector.new(10,10,10)
46         min = vector.subtract(pos, area)
47         max = vector.add(pos, area)
48         area_index = minetest.find_nodes_in_area_under_air(min, max, all_nodes)
49         spawn_table = {}
50         --find the highest y value
51         for _,index in pairs(area_index) do
52                 if not spawn_table[index.x] then spawn_table[index.x] = {} end
53                 if not spawn_table[index.x][index.z] then
54                         spawn_table[index.x][index.z] = index.y
55                 elseif spawn_table[index.x][index.z] < index.y then
56                         spawn_table[index.x][index.z] = index.y
57                 end
58         end
59
60         if defined_type == "rain" then
61         curr_light = minetest.get_node_light(minetest.camera:get_pos(),0.5)
62         --rain sound effect
63         if curr_light then
64                 current_node = minetest.get_node_or_nil(minetest.camera:get_pos())
65
66                 if curr_light >= 15 and current_node and not liquids[current_node.name] then
67                         if not rain_sound_handle then
68                                 rain_sound_handle = minetest.sound_play("rain", {loop=true,gain=0})
69                         end
70                         minetest.sound_fade(rain_sound_handle, 0.5, 1)
71                 elseif rain_sound_handle then
72                         minetest.sound_fade(rain_sound_handle, -0.5, 0)
73                         rain_sound_handle = nil
74                 end
75         end
76
77         particle_table = {
78                 amount = 3,
79                 time = 0.5,
80                 minvel = {x=0, y=-30, z=0},
81                 maxvel = {x=0, y=-30, z=0},
82                 minacc = {x=0, y=0, z=0},
83                 maxacc = {x=0, y=0, z=0},
84                 minexptime = 0.5,
85                 maxexptime = 0.5,
86                 minsize = 4,
87                 maxsize = 4,
88                 collisiondetection = true,
89                 collision_removal = true,
90                 object_collision = false,
91                 vertical = true,
92                 texture = "raindrop.png^[opacity:80",
93         }
94         elseif defined_type == "snow" then
95         particle_table = {
96                 amount = 1,
97                 time = 0.5,
98                 minvel = {x=-0.2, y=-0.2, z=-0.2},
99                 maxvel = {x=0.2, y=-0.5, z=0.2},
100                 minacc = {x=0, y=0, z=0},
101                 maxacc = {x=0, y=0, z=0},
102                 minexptime = 1,
103                 maxexptime = 1,
104                 minsize = 1,
105                 maxsize = 1,
106                 collisiondetection = true,
107                 collision_removal = true,
108                 object_collision = false,
109                 texture = "snowflake_"..math.random(1,2)..".png",
110         }
111         elseif defined_type == "ichor" then
112         particle_table = {
113                 amount = 1,
114                 time = 0.5,
115                 minvel = {x=-0.2, y=0.2, z=-0.2},
116                 maxvel = {x=0.2, y=0.5, z=0.2},
117                 minacc = {x=0, y=0, z=0},
118                 maxacc = {x=0, y=0, z=0},
119                 minexptime = 1,
120                 maxexptime = 1,
121                 minsize = 1,
122                 maxsize = 1,
123                 collisiondetection = true,
124                 collision_removal = true,
125                 object_collision = false,
126                 texture = "ichor_"..math.random(1,2)..".png",
127         }
128         end
129
130
131         for x = min.x,max.x do
132                 for z = min.z,max.z do
133                         if distance({x=x,y=0,z=z},{x=pos.x,y=0,z=pos.z}) <= 10 then
134                                 y = pos.y - 5
135                                 if spawn_table[x] and spawn_table[x][z] then
136                                         y = spawn_table[x][z]
137                                 end
138                                 if minetest.get_node_or_nil(vector.new(x,y+1,z)) ~= nil then
139                                         lightlevel = minetest.get_node_light(vector.new(x,y+1,z), 0.5)
140                                         if lightlevel >= 14 or defined_type == "ichor" then
141
142                                                 particle_table.minpos = vector.new(x-0.5,y,z-0.5)
143                                                 particle_table.maxpos = vector.new(x+0.5,y+20,z+0.5)
144
145                                                 null = minetest.add_particlespawner(particle_table)
146                                         end
147                                 end
148                         end
149                 end
150         end
151 end
152
153
154
155
156 --client runs through spawning weather particles
157 local player_pos
158 local current_node
159 local function update_weather()
160         player_pos = minetest.localplayer:get_pos()
161         if do_effects then
162                 if snow or rain then
163                         current_node = minetest.get_node_or_nil(minetest.camera:get_pos())
164                         if current_node and not liquids[current_node.name] then
165                                 --do normal weather
166                                 if player_pos.y > -10033 then
167                                         if snow == true then
168                                                 weather_effects(minetest.localplayer, "snow")
169                                         elseif rain == true then
170                                                 weather_effects(minetest.localplayer, "rain")
171                                         end
172                                 --rain blood upwards in the nether
173                                 else
174                                         if snow == true or rain == true then
175                                                 weather_effects(minetest.localplayer, "ichor")
176                                         end
177                                 
178                                         --stop the rain sound effect
179                                         if rain_sound_handle then
180                                                 minetest.sound_fade(rain_sound_handle, -0.5, 0)
181                                                 rain_sound_handle = nil
182                                         end
183                                 end
184                         elseif rain_sound_handle then
185                                 minetest.sound_fade(rain_sound_handle, -0.5, 0)
186                                 rain_sound_handle = nil
187                         end
188                 end
189         end
190
191         if not rain and rain_sound_handle then
192                 minetest.sound_fade(rain_sound_handle, -0.5, 0)
193                 rain_sound_handle = nil
194         end
195         --do again every half second
196         minetest.after(0.5, function()
197                 update_weather()
198         end)
199 end
200
201 minetest.register_on_modchannel_message(function(channel_name, sender, message)
202         --receive the initial packet which tells the client which nodes
203         --to spawn weather columns on
204         if sender == "" and channel_name == "weather_nodes" then
205                 all_nodes = minetest.deserialize(message)
206                 nodes = {}
207                 for _,key in pairs(all_nodes) do
208                         nodes[key] = true
209                 end
210                 do_effects = true
211                 weather:leave() --leave the channel
212         end
213         --receive the weather type
214         if sender == "" and channel_name == "weather_type" then
215                 if message == "1" then
216                         rain = false
217                         snow = true
218                 elseif message == "2" then
219                         rain = true
220                         snow = false
221                 else
222                         rain = false
223                         snow = false
224                 end
225         end
226 end)
227
228
229 --We must tell the server that we're ready
230 minetest.after(0,function()
231         weather_intake:send_all("READY")
232         weather_intake:leave()
233         weather_intake = nil --leave the channel
234         
235         --begin weather update
236         update_weather()
237 end)