]> git.lizzy.rs Git - Crafter.git/blob - mods/weather/init.lua
906e960a7d56e9f38edb6e233a55ec7f9207c23c
[Crafter.git] / mods / weather / init.lua
1 local weather_channel = minetest.mod_channel_join("weather_type")
2 local weather_intake = minetest.mod_channel_join("weather_intake")
3 local weather_nodes_channel = minetest.mod_channel_join("weather_nodes")
4
5
6 local weather_max = 2
7 weather_type = math.random(0,weather_max)
8 local weather_timer = 0
9
10 local path = minetest.get_modpath(minetest.get_current_modname())
11 dofile(path.."/commands.lua")
12
13
14 --this updates players skys since it cannot be done clientside
15 update_player_sky = function()
16         for _,player in ipairs(minetest.get_connected_players()) do
17                 if weather_type ~= 0 then
18                         player:set_sky({
19                                 base_color="#808080",
20                                 type="plain",
21                                 clouds=false,
22                                 
23                                 day_sky = "#808080",
24                                 dawn_horizon = "#808080",
25                                 dawn_sky = "#808080",
26                                 fog_sun_tint = "#808080",
27                                 
28                                 night_sky="#808080",
29                                 night_horizon="#808080"
30                         })
31                         player:set_sun({visible=false,sunrise_visible=false})
32                         player:set_moon({visible=false})
33                         player:set_stars({visible=false})
34                 else
35                         player:set_sky({
36                                 base_color="#8cbafa",
37                                 type="regular",
38                                 clouds=true,
39                                 
40                                 day_sky = "#8cbafa",
41                                 
42                                 dawn_horizon = "#bac1f0",
43                                 dawn_sky = "#b4bafa",
44                                 
45                                 night_sky="#006aff",
46                                 night_horizon="#4090ff"
47                         })
48                         
49                         player:set_sun({visible=true,sunrise_visible=true})
50                         player:set_moon({visible=true})
51                         player:set_stars({visible=true})
52                 end
53         end
54 end
55
56 --this tells the client mod to update the weather type
57 function_send_weather_type = function()
58         weather_channel:send_all(tostring(weather_type))
59 end
60
61 --index all mods
62 local all_nodes = {}
63 minetest.register_on_mods_loaded(function()
64         for name in pairs(minetest.registered_nodes) do
65                 if name ~= "air" and name ~= "ignore" then
66                         table.insert(all_nodes,name)
67                 end
68         end     
69 end)
70
71 --this sends the client all nodes that weather can be on top of
72 --(everything)
73
74 --have the client send the server the ready signal
75 minetest.register_on_modchannel_message(function(channel_name, sender, message)
76         if channel_name == "weather_intake" then
77                 print("sending player weather")
78                 --for some reason this variable assignment does not work outside the scope of this function
79                 local all_nodes_serialized = minetest.serialize(all_nodes)
80                 weather_nodes_channel:send_all(all_nodes_serialized)
81                 function_send_weather_type()
82                 update_player_sky()
83         end
84 end)
85
86
87 --spawn snow nodes
88 local pos
89 local area = vector.new(80,40,80)
90 local min
91 local max
92 local subber = vector.subtract
93 local adder  = vector.add
94 local area_index
95 local under_air = minetest.find_nodes_in_area_under_air
96 local area
97 local round_it = vector.round
98 local randomize_number = math.random
99 local n_vec = vector.new
100 local lightlevel
101 local get_light = minetest.get_node_light
102 local g_node = minetest.get_node
103 local node
104 local def
105 local buildable
106 local walkable
107 local liquid
108 local r_nodes = minetest.registered_nodes
109 local bulk_list
110 local ice_list
111 local spawn_table
112 local mass_set = minetest.bulk_set_node
113 local inserter = table.insert
114 local temp_pos
115 local get_table_size = table.getn
116
117 --this is debug
118 --local average = {}
119
120 local function do_snow()
121         if weather_type == 1 then
122                 for _,player in ipairs(minetest.get_connected_players()) do
123                         --this is debug
124                         --local t0 = os.clock()
125                         
126                         pos = round_it(player:get_pos())
127                         
128                         area = n_vec(40,40,40)
129                         min = subber(pos, area)
130                         max = adder(pos, area)
131                         
132                         area_index = under_air(min, max, all_nodes)
133                         
134                         spawn_table = {}
135                         
136                         --the highest value is always indexed last in minetest.find_nodes_in_area_under_air, 
137                         --so all that is needed is to iterate through it backwards and hook into the first
138                         --y value on the x and y and ignore the rest
139                         for key = get_table_size(area_index),1,-1 do
140                                 temp_pos = area_index[key]
141                                 if not spawn_table[temp_pos.x] then spawn_table[temp_pos.x] = {} end
142                                 if not spawn_table[temp_pos.x][temp_pos.z] then
143                                         spawn_table[temp_pos.x][temp_pos.z] = temp_pos.y
144                                 end
145                         end
146                         
147                         --save old method just in case useful or turns out it's faster after all
148                         --for _,index in pairs(area_index) do
149                         --      if not spawn_table[index.x] then spawn_table[index.x] = {} end
150                         --      if not spawn_table[index.x][index.z] then
151                         --              spawn_table[index.x][index.z] = index.y
152                         --      elseif spawn_table[index.x][index.z] < index.y then
153                         --              spawn_table[index.x][index.z] = index.y
154                         --      end
155                         --end
156                         
157                         --find the highest y value
158                         bulk_list = {}
159                         ice_list = {}
160                         for x,x_index in pairs(spawn_table) do
161                                 for z,y in pairs(x_index) do
162                                         if randomize_number(1100) >= 1098 then
163                                                 lightlevel = get_light(n_vec(x,y+1,z), 0.5)
164                                                 if lightlevel >= 14 then
165                                                         --make it so buildable to nodes get replaced
166                                                         node = g_node(n_vec(x,y,z)).name
167                                                         def = r_nodes[node]
168                                                         buildable = def.buildable_to
169                                                         walkable = def.walkable
170                                                         liquid = (def.liquidtype ~= "none")
171                                                         
172                                                         if not liquid then
173                                                                 if not buildable and g_node(n_vec(x,y+1,z)).name ~= "weather:snow" and walkable == true then
174                                                                         inserter(bulk_list, n_vec(x,y+1,z))
175                                                                 elseif buildable == true and node ~= "weather:snow" then
176                                                                         inserter(bulk_list, n_vec(x,y,z))
177                                                                 end
178                                                         elseif g_node(n_vec(x,y,z)).name == "main:water" then
179                                                                 inserter(ice_list, n_vec(x,y,z))
180                                                         end
181                                                 end
182                                         end
183                                 end
184                         end
185                         if bulk_list then
186                                 mass_set(bulk_list, {name="weather:snow"})
187                         end
188                         if ice_list then
189                                 mass_set(ice_list, {name="main:ice"})
190                         end
191                         
192                         
193                         --this is debug
194                         --[[
195                         local chugent = math.ceil((os.clock() - t0) * 1000)
196                         print("---------------------------------")
197                         print ("Snow generation time " .. chugent .. " ms")
198
199                         inserter(average, chugent)
200                         local a = 0
201                         --don't cause memory leak
202                         if get_table_size(average) > 10 then
203                                 table.remove(average,1)
204                         end
205                         for _,i in ipairs(average) do
206                                 a = a + i
207                         end
208                         print(dump(average))
209                         a = a / get_table_size(average)
210                         print("average = "..a.."ms")
211                         print("---------------------------------")
212                         ]]--
213                 end
214         end
215         
216         minetest.after(3, function()
217                 do_snow()
218         end)
219 end
220 minetest.register_on_mods_loaded(function()
221         minetest.after(0,function()
222                 do_snow()
223         end)
224 end)
225
226
227
228 --this sets random weather
229 local weather_timer_goal = (math.random(5,7)+math.random())*60
230 --minetest.register_globalstep(function(dtime)
231 local function randomize_weather()
232         weather_type = math.random(0,weather_max)
233         function_send_weather_type()
234         update_player_sky()
235         minetest.after((math.random(5,7)+math.random())*60, function()
236                 randomize_weather()
237         end)
238 end
239 minetest.register_on_mods_loaded(function()
240         minetest.after(0,function()
241                 randomize_weather()
242         end)
243 end)
244
245 local snowball_throw = function(player)
246         local pos = player:get_pos()
247         pos.y = pos.y + 1.625
248         --let other players hear the noise too
249         minetest.sound_play("woosh",{to_player=player:get_player_name(), pitch = math.random(80,100)/100})
250         minetest.sound_play("woosh",{pos=pos, exclude_player = player:get_player_name(), pitch = math.random(80,100)/100})
251         local snowball = minetest.add_entity(pos,"weather:snowball")
252         if snowball then
253                 local vel = player:get_player_velocity()
254                 snowball:set_velocity(vector.add(vel,vector.multiply(player:get_look_dir(),20)))
255                 snowball:get_luaentity().thrower = player:get_player_name()
256                 return(true)
257         end
258         return(false)
259 end
260
261 minetest.register_node("weather:snow", {
262     description = "Snow",
263     tiles = {"snow_block.png"},
264     groups = {pathable = 1,snow = 1, falling_node=1},
265     sounds = main.woolSound(),
266     paramtype = "light",
267         drawtype = "nodebox",
268         walkable = false,
269         floodable = true,
270     drop = {
271                         max_items = 5,
272                         items= {
273                                 {
274                                         items = {"weather:snowball"},
275                                 },
276                                 {
277                                         items = {"weather:snowball"},
278                                 },
279                                 {
280                                         items = {"weather:snowball"},
281                                 },
282                                 {
283                                         items = {"weather:snowball"},
284                                 },
285                                 {
286                                         rarity = 5,
287                                         items = {"weather:snowball"},
288                                 },
289                         },
290                 },
291     buildable_to = true,
292     node_box = {
293                 type = "fixed",
294                 fixed = {
295                 {-8/16, -8/16, -8/16, 8/16, -6/16, 8/16},
296                 }
297         },
298 })
299
300 minetest.register_node("weather:snow_block", {
301     description = "Snow",
302     tiles = {"snow_block.png"},
303     groups = {pathable = 1,snow = 1},
304     sounds = main.woolSound(),
305     drop = {
306                         max_items = 5,
307                         items= {
308                                 {
309                                         items = {"weather:snowball"},
310                                 },
311                                 {
312                                         items = {"weather:snowball"},
313                                 },
314                                 {
315                                         items = {"weather:snowball"},
316                                 },
317                                 {
318                                         items = {"weather:snowball"},
319                                 },
320                                 {
321                                         rarity = 5,
322                                         items = {"weather:snowball"},
323                                 },
324                         },
325                 },
326 })
327
328 minetest.register_craftitem("weather:snowball", {
329         description = "Snowball",
330         inventory_image = "snowball.png",
331         --stack_max = 1,
332         --range = 0,
333         on_place = function(itemstack, placer, pointed_thing)
334                 local worked = snowball_throw(placer)
335                 if worked then
336                         itemstack:take_item()
337                 end
338                 return(itemstack)
339         end,
340         on_secondary_use = function(itemstack, user, pointed_thing)
341                 local worked = snowball_throw(user)
342                 if worked then
343                         itemstack:take_item()
344                 end
345                 return(itemstack)
346         end,
347 })
348
349
350 snowball = {}
351 snowball.initial_properties = {
352         hp_max = 1,
353         physical = true,
354         collide_with_objects = false,
355         collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
356         visual = "sprite",
357         visual_size = {x = 0.5, y = 0.5},
358         textures = {
359                 "snowball.png"
360         },
361         is_visible = true,
362         pointable = false,
363 }
364
365 snowball.snowball = true
366
367 snowball.on_activate = function(self)
368         self.object:set_acceleration(vector.new(0,-9.81,0))
369 end
370
371 --make this as efficient as possible
372 --make it so you can hit one snowball with another
373 snowball.on_step = function(self, dtime)
374         local vel = self.object:get_velocity()
375         local hit = false
376         local pos = self.object:get_pos()
377         
378         --hit object with the snowball
379         for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
380                 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
381                         object:punch(self.object, 2, 
382                                 {
383                                 full_punch_interval=1.5,
384                                 damage_groups = {damage=0},
385                         })
386                         hit = true
387                         break
388                 end
389         end
390         
391         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
392         
393                 minetest.sound_play("wool",{pos=pos, pitch = math.random(80,100)/100})
394                 minetest.add_particlespawner({
395                         amount = 20,
396                         -- Number of particles spawned over the time period `time`.
397
398                         time = 0.001,
399                         -- Lifespan of spawner in seconds.
400                         -- If time is 0 spawner has infinite lifespan and spawns the `amount` on
401                         -- a per-second basis.
402
403                         minpos = pos,
404                         maxpos = pos,
405                         minvel = {x=-2, y=3, z=-2},
406                         maxvel = {x=2, y=5, z=2},
407                         minacc = {x=0, y=-9.81, z=0},
408                         maxacc = {x=0, y=-9.81, z=0},
409                         minexptime = 1,
410                         maxexptime = 3,
411                         minsize = 1,
412                         maxsize = 1,
413                         -- The particles' properties are random values between the min and max
414                         -- values.
415                         -- pos, velocity, acceleration, expirationtime, size
416
417                         collisiondetection = true,
418
419                         collision_removal = true,
420
421                         object_collision = false,
422
423                         texture = "snowflake_"..math.random(1,2)..".png",
424
425                 })
426                 
427                 self.object:remove()
428                 
429         end
430         
431         self.oldvel = vel
432 end
433 minetest.register_entity("weather:snowball", snowball)