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")
7 weather_type = math.random(0,weather_max)
8 local weather_timer = 0
10 local path = minetest.get_modpath(minetest.get_current_modname())
11 dofile(path.."/commands.lua")
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
24 dawn_horizon = "#808080",
26 fog_sun_tint = "#808080",
29 night_horizon="#808080"
31 player:set_sun({visible=false,sunrise_visible=false})
32 player:set_moon({visible=false})
33 player:set_stars({visible=false})
42 dawn_horizon = "#bac1f0",
46 night_horizon="#4090ff"
49 player:set_sun({visible=true,sunrise_visible=true})
50 player:set_moon({visible=true})
51 player:set_stars({visible=true})
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))
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)
71 --this sends the client all nodes that weather can be on top of
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()
89 local area = vector.new(80,40,80)
92 local subber = vector.subtract
93 local adder = vector.add
95 local under_air = minetest.find_nodes_in_area_under_air
97 local round_it = vector.round
98 local randomize_number = math.random
99 local n_vec = vector.new
101 local get_light = minetest.get_node_light
102 local g_node = minetest.get_node
108 local r_nodes = minetest.registered_nodes
112 local mass_set = minetest.bulk_set_node
113 local inserter = table.insert
115 local get_table_size = table.getn
120 local function do_snow()
121 if weather_type == 1 then
122 for _,player in ipairs(minetest.get_connected_players()) do
124 --local t0 = os.clock()
126 pos = round_it(player:get_pos())
128 area = n_vec(40,40,40)
129 min = subber(pos, area)
130 max = adder(pos, area)
132 area_index = under_air(min, max, all_nodes)
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
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
157 --find the highest y value
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
168 buildable = def.buildable_to
169 walkable = def.walkable
170 liquid = (def.liquidtype ~= "none")
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))
178 elseif g_node(n_vec(x,y,z)).name == "main:water" then
179 inserter(ice_list, n_vec(x,y,z))
186 mass_set(bulk_list, {name="weather:snow"})
189 mass_set(ice_list, {name="main:ice"})
195 local chugent = math.ceil((os.clock() - t0) * 1000)
196 print("---------------------------------")
197 print ("Snow generation time " .. chugent .. " ms")
199 inserter(average, chugent)
201 --don't cause memory leak
202 if get_table_size(average) > 10 then
203 table.remove(average,1)
205 for _,i in ipairs(average) do
209 a = a / get_table_size(average)
210 print("average = "..a.."ms")
211 print("---------------------------------")
216 minetest.after(3, function()
220 minetest.register_on_mods_loaded(function()
221 minetest.after(0,function()
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()
235 minetest.after((math.random(5,7)+math.random())*60, function()
239 minetest.register_on_mods_loaded(function()
240 minetest.after(0,function()
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")
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()
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(),
267 drawtype = "nodebox",
274 items = {"weather:snowball"},
277 items = {"weather:snowball"},
280 items = {"weather:snowball"},
283 items = {"weather:snowball"},
287 items = {"weather:snowball"},
295 {-8/16, -8/16, -8/16, 8/16, -6/16, 8/16},
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(),
309 items = {"weather:snowball"},
312 items = {"weather:snowball"},
315 items = {"weather:snowball"},
318 items = {"weather:snowball"},
322 items = {"weather:snowball"},
328 minetest.register_craftitem("weather:snowball", {
329 description = "Snowball",
330 inventory_image = "snowball.png",
333 on_place = function(itemstack, placer, pointed_thing)
334 local worked = snowball_throw(placer)
336 itemstack:take_item()
340 on_secondary_use = function(itemstack, user, pointed_thing)
341 local worked = snowball_throw(user)
343 itemstack:take_item()
351 snowball.initial_properties = {
354 collide_with_objects = false,
355 collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
357 visual_size = {x = 0.5, y = 0.5},
365 snowball.snowball = true
367 snowball.on_activate = function(self)
368 self.object:set_acceleration(vector.new(0,-9.81,0))
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()
376 local pos = self.object:get_pos()
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,
383 full_punch_interval=1.5,
384 damage_groups = {damage=0},
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
393 minetest.sound_play("wool",{pos=pos, pitch = math.random(80,100)/100})
394 minetest.add_particlespawner({
396 -- Number of particles spawned over the time period `time`.
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.
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},
413 -- The particles' properties are random values between the min and max
415 -- pos, velocity, acceleration, expirationtime, size
417 collisiondetection = true,
419 collision_removal = true,
421 object_collision = false,
423 texture = "snowflake_"..math.random(1,2)..".png",
433 minetest.register_entity("weather:snowball", snowball)