/
init.lua
283 lines (244 loc) · 7.03 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
if minetest.settings:get_bool("enable_weather") == false then
return
end
local translator = minetest.get_translator
local S = translator and translator("weather_lite") or function(s) return s end
local vadd, vmultiply, vround = vector.add, vector.multiply, vector.round
local random = math.random
local snow_covers = minetest.settings:get_bool("weather_snow_covers") ~= false
local weather = {
type = "none",
wind = {x = 0, y = 0, z = 0}
}
--
-- Save and restore weather condition
--
local mod_storage = minetest.get_mod_storage()
do
local saved_weather = minetest.deserialize(
mod_storage:get_string("weather"))
if type(saved_weather) == "table" then
weather = saved_weather
end
end
minetest.register_on_shutdown(function()
mod_storage:set_string("weather", minetest.serialize(
({type = weather.type, wind = weather.wind})))
end)
--
-- Registration of weather types
--
weather.registered = {}
function weather.register(id, def)
local ndef = table.copy(def)
weather.registered[id] = ndef
end
-- Rain
weather.register("rain", {
desc = S("Rain"),
falling_speed = 5,
amount = 6,
size = 20,
height = 3,
vertical = true,
texture = "weather_lite_rain.png"
})
-- Snow
weather.register("snow", {
desc = S("Snow"),
falling_speed = 2,
amount = 5,
size = 35,
height = 2,
texture = "weather_lite_snow.png"
})
--
-- Change of weather
--
function weather.set(weather_type, wind)
weather.type = weather_type
if wind then
weather.wind = wind
end
if minetest.global_exists("sscsm") then
sscsm.com_send_all("weather_lite:set", {
type = weather_type,
wind = wind
})
end
end
local function weather_change(disable)
if weather.type == "none" and not disable then
for w in pairs(weather.registered) do
if random(3) == 1 then
weather.set(w, {
x = random(0, 8),
y = 0,
z = random(0, 8)
})
break
end
end
minetest.after(random(60, 300), function() weather_change(true) end)
else
weather.set("none")
minetest.after(random(1800, 3600), weather_change)
end
end
minetest.after(random(600, 1800), weather_change)
--
-- Processing players
--
local is_valid_pos = minetest.is_valid_pos
if not is_valid_pos then
is_valid_pos = function() return true end
end
-- This is a separate function to prevent "return" from breaking.
local function process_player(player, current_downfall)
local player_name = player:get_player_name()
if not player:is_player() or (sscsm and sscsm.has_sscsms_enabled(player_name)) then
return
end
local ppos = vround(player:get_pos())
ppos.y = ppos.y + 1.5
-- Higher than clouds
local cloud_height = player:get_clouds().height
cloud_height = cloud_height ~= 0 and cloud_height or 120
if not is_valid_pos(ppos) or ppos.y > cloud_height or ppos.y < -8 then return end
-- Inside liquid
local head_inside = minetest.get_node_or_nil(ppos)
local def_inside = head_inside and minetest.registered_nodes[head_inside.name]
if def_inside and def_inside.drawtype == "liquid" then return end
-- Too dark, probably not under the sky
local light = minetest.get_node_light(ppos, 0.5)
if light and light < 12 then return end
local wind_pos = vmultiply(weather.wind, -1)
local minp = vadd(vadd(ppos, {x = -8, y = current_downfall.height, z = -8}), wind_pos)
local maxp = vadd(vadd(ppos, {x = 8, y = current_downfall.height, z = 8}), wind_pos)
local vel = {x = weather.wind.x, y = -current_downfall.falling_speed, z = weather.wind.z}
local vert = current_downfall.vertical or false
minetest.add_particlespawner({
amount = current_downfall.amount,
time = 0.1,
minpos = minp,
maxpos = maxp,
minvel = vel,
maxvel = vel,
minsize = current_downfall.size,
maxsize = current_downfall.size,
collisiondetection = true,
collision_removal = true,
vertical = vert,
texture = current_downfall.texture,
glow = 1,
playername = player_name
})
end
minetest.register_globalstep(function()
local current_downfall = weather.registered[weather.type]
if current_downfall == nil then return end
for _, player in ipairs(minetest.get_connected_players()) do
process_player(player, current_downfall)
end
end)
--
-- Snow will cover the blocks and melt after some time
--
if snow_covers then
-- Temp node to start the node timer
minetest.register_node("weather_lite:snow_cover", {
tiles = {"blank.png"},
drawtype = "signlike",
paramtype = "light",
buildable_to = true,
groups = {not_in_creative_inventory = 1, dig_immediate = 3},
on_construct = function(pos)
minetest.get_node_timer(pos):start(random(60, 180))
minetest.swap_node(pos, {name = "default:snow"})
end
})
minetest.override_item("default:snow", {
on_timer = function(pos)
if weather and weather.type and weather.type == "snow" then
return true
end
minetest.remove_node(pos)
end
})
minetest.register_abm({
label = "Weather: snow cover",
nodenames = {"group:crumbly", "group:snappy", "group:cracky", "group:choppy"},
neighbors = {"air"},
interval = 15,
chance = 500,
catch_up = false,
action = function(pos, node)
if weather.type == "snow" then
if pos.y < -8 or pos.y > 120 then return end
if minetest.registered_nodes[node.name].drawtype == "normal"
or minetest.registered_nodes[node.name].drawtype == "allfaces_optional" then
pos.y = pos.y + 1
if minetest.get_node(pos).name ~= "air" then return end
local light_day = minetest.get_node_light(pos, 0.5)
local light_night = minetest.get_node_light(pos, 0)
if light_day and light_day == 15
and light_night and light_night < 10 then
minetest.add_node(pos, {name = "weather_lite:snow_cover"})
end
end
end
end
})
end
minetest.register_privilege("weather", {
description = "Allows changing the weather",
give_to_singleplayer = minetest.settings:get_bool("creative_mode")
})
minetest.register_chatcommand("weather", {
params = "<weather>",
description = S("Setting the weather type"),
privs = {weather = true},
func = function(name, param)
if param and (weather.registered[param] or param == "none") then
weather.set(param)
if param == "none" then
minetest.chat_send_player(name, S("Set clear weather."))
else
local setw = weather.registered[param].desc or param:gsub("^%l", string.upper)
minetest.chat_send_player(name, S("Set weather type: @1.", setw))
end
else
local types = "none"
for w in pairs(weather.registered) do
types = types .. ", " .. w
end
minetest.chat_send_player(name, S("Avalible weather types: @1.", types))
end
end
})
if not minetest.global_exists("sscsm") then
return
end
sscsm.register({
name = "weather_lite",
file = minetest.get_modpath("weather_lite") .. "/sscsm.lua"
})
local liquids
sscsm.register_on_sscsms_loaded(function(name)
if not liquids then
liquids = {}
for node, def in pairs(minetest.registered_nodes) do
if def.drawtype == "liquid" then
liquids[node] = true
end
end
end
local player = minetest.get_player_by_name(name)
sscsm.com_send(name, "weather_lite:set", {
type = weather.type,
wind = weather.wind,
registered = weather.registered,
cloud_height = player:get_clouds().height,
liquids = liquids
})
end)