]> git.lizzy.rs Git - Crafter.git/blob - mods/weather/init.lua
Overhaul weather and add in rain
[Crafter.git] / mods / weather / init.lua
1 local weather_max = 2
2 local weather_type = math.random(0,weather_max)
3 local weather_timer = 0
4
5
6
7 --this updates players skys since it cannot be done clientside
8 local update_player_sky = function()
9         for _,player in ipairs(minetest.get_connected_players()) do
10                 if weather_type ~= 0 then
11                         player:set_sky({
12                                 base_color="#808080",
13                                 type="plain",
14                                 clouds=false,
15                                 
16                                 day_sky = "#808080",
17                                 dawn_horizon = "#808080",
18                                 dawn_sky = "#808080",
19                                 fog_sun_tint = "#808080",
20                                 
21                                 night_sky="#808080",
22                                 night_horizon="#808080"
23                         })
24                         player:set_sun({visible=false,sunrise_visible=false})
25                         player:set_moon({visible=false})
26                         player:set_stars({visible=false})
27                 else
28                         player:set_sky({
29                                 base_color="#8cbafa",
30                                 type="regular",
31                                 clouds=true,
32                                 
33                                 day_sky = "#8cbafa",
34                                 
35                                 dawn_horizon = "#bac1f0",
36                                 dawn_sky = "#b4bafa",
37                                 
38                                 night_sky="#006aff",
39                                 night_horizon="#4090ff"
40                         })
41                         
42                         player:set_sun({visible=true,sunrise_visible=true})
43                         player:set_moon({visible=true})
44                         player:set_stars({visible=true})
45                 end
46         end
47 end
48
49 --this tells the client mod to update the weather type
50 local function_send_weather_type = function()
51         local channel = minetest.mod_channel_join("weather_type")
52         channel:send_all(tostring(weather_type))
53         channel:leave()
54 end
55
56 --index all mods
57 local all_nodes = {}
58 minetest.register_on_mods_loaded(function()
59         for name in pairs(minetest.registered_nodes) do
60                 if name ~= "air" and name ~= "ignore" then
61                         table.insert(all_nodes,name)
62                 end
63         end     
64 end)
65
66 --this sends the client all nodes that weather can be on top of
67 --(everything)
68 minetest.register_on_joinplayer(function(player)
69         minetest.after(5, function()
70                 
71                 local text = minetest.serialize(all_nodes)
72                 local channel = minetest.mod_channel_join("weather_nodes")
73                 channel:send_all(text)
74                 channel:leave()
75                 
76                 function_send_weather_type()
77                 update_player_sky()
78         end)
79 end)
80
81
82 --spawn snow nodes
83 local snow_timer = 0
84 local do_snow = function(dtime)
85         snow_timer = snow_timer + dtime
86         if snow_timer > 3 then
87                 snow_timer = 0
88                 for _,player in ipairs(minetest.get_connected_players()) do
89                         --print("running")
90                         local pos = player:get_pos()
91                         
92                         local meta = player:get_meta()
93                         local particle_table = {}
94                         
95                         local area = vector.new(40,40,40)
96                         
97                         local min = vector.subtract(pos, area)
98                         local max = vector.add(pos, area)
99                         
100                         
101                         local area_index = minetest.find_nodes_in_area_under_air(min, max, all_nodes)
102                         
103
104                         local spawn_table = {}
105                         for _,index in pairs(area_index) do
106                                 if not spawn_table[index.x] then spawn_table[index.x] = {} end
107                                 if not spawn_table[index.x][index.z] then
108                                         spawn_table[index.x][index.z] = index.y
109                                 elseif spawn_table[index.x][index.z] < index.y then
110                                         spawn_table[index.x][index.z] = index.y
111                                 end
112                         end
113                 
114                         
115                         --find the highest y value
116                         local bulk_list = {}
117                         for x,x_index in pairs(spawn_table) do
118                                 for z,y in pairs(x_index) do
119                                         if math.random() > 0.995 then
120                                                 local lightlevel = minetest.get_node_light(vector.new(x,y+1,z), 0.5)
121                                                 if lightlevel >= 14 then
122                                                         --make it so buildable to nodes get replaced
123                                                         local node = minetest.get_node(vector.new(x,y,z)).name
124                                                         local def = minetest.registered_nodes[node]
125                                                         local buildable = def.buildable_to
126                                                         local walkable = def.walkable
127                                                         local liquid = (def.liquidtype ~= "none")
128                                                         
129                                                         if not liquid then
130                                                                 if not buildable and minetest.get_node(vector.new(x,y+1,z)).name ~= "weather:snow" and walkable == true then
131                                                                         table.insert(bulk_list, vector.new(x,y+1,z))
132                                                                 elseif buildable == true and node ~= "weather:snow" then
133                                                                         table.insert(bulk_list, vector.new(x,y,z))
134                                                                 end
135                                                         end
136                                                 end
137                                         end
138                                 end
139                         end
140                         if bulk_list then
141                                 minetest.bulk_set_node(bulk_list, {name="weather:snow"})
142                         end
143                 end
144         end
145 end
146
147
148
149 --this sets random weather
150 local weather_timer_goal = (math.random(5,7)+math.random())*60
151 minetest.register_globalstep(function(dtime)
152         weather_timer = weather_timer + dtime
153         if weather_timer >= weather_timer_goal then
154                 weather_timer_goal = (math.random(5,7)+math.random())*60
155                 weather_timer = 0
156                 weather_type = math.random(0,weather_max)
157                 function_send_weather_type()
158                 update_player_sky()
159         end
160         --spawn snow nodes
161         if weather_type == 1 then
162                 do_snow(dtime)
163         end
164 end)
165
166 local snowball_throw = function(player)
167         local pos = player:get_pos()
168         pos.y = pos.y + 1.625
169         --let other players hear the noise too
170         minetest.sound_play("woosh",{to_player=player:get_player_name(), pitch = math.random(80,100)/100})
171         minetest.sound_play("woosh",{pos=pos, exclude_player = player:get_player_name(), pitch = math.random(80,100)/100})
172         local snowball = minetest.add_entity(pos,"weather:snowball")
173         if snowball then
174                 local vel = player:get_player_velocity()
175                 snowball:set_velocity(vector.add(vel,vector.multiply(player:get_look_dir(),20)))
176                 snowball:get_luaentity().thrower = player:get_player_name()
177                 return(true)
178         end
179         return(false)
180 end
181
182 minetest.register_node("weather:snow", {
183     description = "Snow",
184     tiles = {"snow_block.png"},
185     groups = {soft = 1, shovel = 1, hand = 1,pathable = 1,wool=1,dirt=1,falling_node=1},
186     sounds = main.woolSound(),
187     paramtype = "light",
188         drawtype = "nodebox",
189     drop = {
190                         max_items = 5,
191                         items= {
192                                 {
193                                         items = {"weather:snowball"},
194                                 },
195                                 {
196                                         items = {"weather:snowball"},
197                                 },
198                                 {
199                                         items = {"weather:snowball"},
200                                 },
201                                 {
202                                         items = {"weather:snowball"},
203                                 },
204                                 {
205                                         rarity = 5,
206                                         items = {"weather:snowball"},
207                                 },
208                         },
209                 },
210     buildable_to = true,
211     node_box = {
212                 type = "fixed",
213                 fixed = {
214                 {-8/16, -8/16, -8/16, 8/16, -6/16, 8/16},
215                 }
216         },
217 })
218
219 minetest.register_craftitem("weather:snowball", {
220         description = "Snowball",
221         inventory_image = "snowball.png",
222         --stack_max = 1,
223         --range = 0,
224         on_place = function(itemstack, placer, pointed_thing)
225                 local worked = snowball_throw(placer)
226                 if worked then
227                         itemstack:take_item()
228                 end
229                 return(itemstack)
230         end,
231         on_secondary_use = function(itemstack, user, pointed_thing)
232                 local worked = snowball_throw(user)
233                 if worked then
234                         itemstack:take_item()
235                 end
236                 return(itemstack)
237         end,
238 })
239
240
241 snowball = {}
242 snowball.initial_properties = {
243         hp_max = 1,
244         physical = true,
245         collide_with_objects = false,
246         collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
247         visual = "sprite",
248         visual_size = {x = 0.5, y = 0.5},
249         textures = {
250                 "snowball.png"
251         },
252         is_visible = true,
253         pointable = false,
254 }
255
256 snowball.snowball = true
257
258 snowball.on_activate = function(self)
259         self.object:set_acceleration(vector.new(0,-9.81,0))
260 end
261
262 --make this as efficient as possible
263 --make it so you can hit one snowball with another
264 snowball.on_step = function(self, dtime)
265         local vel = self.object:get_velocity()
266         local hit = false
267         local pos = self.object:get_pos()
268         
269         --hit object with the snowball
270         for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
271                 if (object:is_player() and object:get_hp() > 0 and object:get_player_name() ~= self.thrower) or (object:get_luaentity() and object:get_luaentity().mob == true) then
272                         object:punch(self.object, 2, 
273                                 {
274                                 full_punch_interval=1.5,
275                                 damage_groups = {fleshy=0},
276                         })
277                         hit = true
278                         break
279                 end
280         end
281         
282         if (self.oldvel and ((vel.x == 0 and self.oldvel.x ~= 0) or (vel.y == 0 and self.oldvel.y ~= 0) or (vel.z == 0 and self.oldvel.z ~= 0))) or hit == true then
283         
284                 minetest.sound_play("wool",{pos=pos, pitch = math.random(80,100)/100})
285                 minetest.add_particlespawner({
286                         amount = 20,
287                         -- Number of particles spawned over the time period `time`.
288
289                         time = 0.001,
290                         -- Lifespan of spawner in seconds.
291                         -- If time is 0 spawner has infinite lifespan and spawns the `amount` on
292                         -- a per-second basis.
293
294                         minpos = pos,
295                         maxpos = pos,
296                         minvel = {x=-2, y=3, z=-2},
297                         maxvel = {x=2, y=5, z=2},
298                         minacc = {x=0, y=-9.81, z=0},
299                         maxacc = {x=0, y=-9.81, z=0},
300                         minexptime = 1,
301                         maxexptime = 3,
302                         minsize = 1,
303                         maxsize = 1,
304                         -- The particles' properties are random values between the min and max
305                         -- values.
306                         -- pos, velocity, acceleration, expirationtime, size
307
308                         collisiondetection = true,
309
310                         collision_removal = true,
311
312                         object_collision = false,
313
314                         texture = "snowflake_"..math.random(1,2)..".png",
315
316                 })
317                 
318                 self.object:remove()
319                 
320         end
321         
322         self.oldvel = vel
323 end
324 minetest.register_entity("weather:snowball", snowball)