Differences From
Artifact [d1f4916ac1]:
42 42 surfaceTemp = heat;
43 43 waterTemp = heat + biome.waterTempDelta;
44 44 surfaceHumid = humid;
45 45 }
46 46 end
47 47
48 48 local vdsq = lib.math.vdsq
49 -function world.climate.temp(pos) --> irradiance at pos in W
49 +function world.climate.temp(pos, timeshift) --> irradiance at pos in W
50 50 local cl = world.climate.eval(pos)
51 51 local radCenters = starlit.region.radiator.store:get_areas_for_pos(pos, false, true)
52 52 local irradiance = 0
53 53 for _,e in pairs(radCenters) do
54 54 local rpos = minetest.string_to_pos(e.data)
55 55 local rdef = assert(minetest.registered_nodes[assert(minetest.get_node(rpos)).name])
56 56 local rc = rdef._starlit.radiator
................................................................................
79 79 power = power * (1 - (dist_sq / ((r_max+1)^2)))
80 80 end
81 81 power = power * (1 - (obstruct/5))
82 82 irradiance = irradiance + power
83 83 end
84 84 end
85 85 end
86 + local w = world.climate.weatherAt(pos, timeshift)
87 +
86 88 return irradiance + cl.surfaceTemp
87 89 end
90 +
91 +function world.ecology.biomeAt(pos)
92 + return world.ecology.biomes.db[minetest.get_biome_name(minetest.get_biome_data(pos).biome)]
93 +end
94 +
95 +
96 +minetest.after(0, function()
97 + world.climate.weatherMap.kind = minetest.get_perlin {
98 + seed = 0x925afe;
99 + octaves = 2;
100 + spread = vector.new(256,256,120);
101 + };
102 + world.climate.weatherMap.severity = minetest.get_perlin {
103 + seed = 0x39de1d;
104 + octaves = 1;
105 + spread = vector.new(256,256,60);
106 + };
107 +end)
108 +
109 +function world.climate.weatherAt(pos, timeshift)
110 + timeshift = timeshift or 0
111 + local wv = world.climate.weatherMap.kind:get_3d(vector.new(pos.x, pos.z, minetest.get_gametime() + timeshift))
112 + local sev = world.climate.weatherMap.severity:get_3d(vector.new(pos.x, pos.z, minetest.get_gametime() + timeshift))
113 + local b = world.ecology.biomeAt(pos)
114 + local w = 'starlit:clear'
115 + for i,v in ipairs(b.weather) do
116 + if wv < v[1] then
117 + w = v[2]
118 + break
119 + end
120 + end
121 + local mods = {
122 + cloudCover = 0;
123 + rain = 0; -- affects plant growth
124 + snow = 0; -- spawns snow layer
125 + fog = 0;
126 + temp = 0;
127 + hum = 0;
128 + rad = 0;
129 + }
130 + return world.climate.weather.db[w], sev
131 +end
132 +
133 +
134 +-- weather manages particle systems, and provides modifiers for
135 +-- temp, cloud cover, received precipitation, and fog
136 +
137 +world.climate.weather.link('starlit:clear', {
138 + name = 'Clear';
139 +})
140 +world.climate.weather.link('starlit:cloudy', {
141 + name = 'Cloudy';
142 + mod = function(m, temp, hum, sev)
143 + m.cloudCover = math.max(m.cloudCover, sev)
144 + end;
145 +})
146 +world.climate.weather.link('starlit:precip', {
147 + name = function(temp, hum, sev)
148 + if temp < 0 then return 'Snow' else return 'Rain' end
149 + end;
150 + mod = function(m, temp, hum, sev)
151 + m.cloudCover = math.max(m.cloudCover, sev)
152 + if temp < 0 then
153 + m.snow = math.max(m.snow, sev/2)
154 + else
155 + m.rain = math.max(m.rain, sev/2)
156 + end
157 + end;
158 +})
159 +world.climate.weather.link('starlit:storm', {
160 + name = function(temp, hum, sev)
161 + if temp < 0 then
162 + if sev > .5
163 + then return 'Blizzard'
164 + else return 'Snowstorm'
165 + end
166 + else
167 + if sev > .5
168 + then return 'Monsoon'
169 + else return 'Rainstorm'
170 + end
171 + end
172 + end;
173 + mod = function(m, temp, hum, sev)
174 + m.cloudCover = math.max(m.cloudCover, sev)
175 + if temp < 0 then
176 + m.snow = math.max(m.snow, sev/2 + .5)
177 + else
178 + m.rain = math.max(m.rain, sev/2 + .5)
179 + end
180 + end;
181 +})
182 +world.climate.weather.link('starlit:tstorm', {
183 + name = 'Thunderstorm';
184 + danger = 1;
185 + mod = function(m, temp, hum, sev)
186 + m.cloudCover = math.max(m.cloudCover, sev)
187 + m.danger = (sev>.5) and 2 or 1
188 + end;
189 +})
190 +world.climate.weather.link('starlit:sstorm', {
191 + name = 'Solar Storm';
192 + danger = 2;
193 +})
194 +world.climate.weather.link('starlit:meteorShower', {
195 + name = 'Meteor Shower';
196 + danger = 2;
197 +})
88 198
89 199 world.ecology.biomes.foreach('starlit:biome-gen', {}, function(id, b)
90 200 b.def.name = id
91 201 minetest.register_biome(b.def)
92 202 end)
93 203
94 204 world.ecology.plants.foreach('starlit:plant-gen', {}, function(id, b)
................................................................................
160 270 }
161 271 for k,v in pairs(b.decoration) do dec[k] = v end
162 272 b.decoration = minetest.register_decoration(dec)
163 273 end)
164 274
165 275 local toward = lib.math.toward
166 276 local hfinterval = 1.5
167 -starlit.startJob('starlit:heatflow', hfinterval, function(delta)
277 +starlit.startJob('starlit:temps', hfinterval, function(delta)
168 278
169 279 -- our base thermal conductivity (κ) is measured in °C/°C/s. say the
170 280 -- player is in -30°C weather, and has an internal temperature of
171 281 -- 10°C. then:
172 282 -- κ = .1°C/C/s (which is apparently 100mHz)
173 283 -- Tₚ = 10°C
174 284 -- Tₑ = -30°C
................................................................................
175 285 -- d = Tₑ − Tₚ = -40°C
176 286 -- ΔT = κ×d = -.4°C/s
177 287 -- too cold:
178 288 -- x = beginning of danger zone
179 289 -- κ × (x - Tₚ) = y where y < Tₚ
180 290 -- our final change in temperature is computed as tΔC where t is time
181 291 local kappa = starlit.constant.heat.thermalConductivity
292 + local now = minetest.get_gametime()
182 293 for name,user in pairs(starlit.activeUsers) do
183 294 local tr = user:species().tempRange
184 295 local t = starlit.world.climate.temp(user.entity:get_pos())
296 +
297 + local weather,wsev = starlit.world.climate.weatherAt(user.entity:get_pos())
298 + local wfac
299 + if user.env.weather == nil
300 + then wfac = 1
301 + else wfac = (now - user.env.weather.when) / 10
302 + end
303 + if user.env.weather == nil or now - user.env.weather.when >= 10 then
304 + user.env.weather = {when = now, what = weather}
305 + end
185 306
186 307 do -- this bit probably belongs in starlit:bio but we do it here in order
187 308 -- to spare ourselves another call into the dark swamp of climate.temp
188 309 local urg = 1
189 310 local hz = user:tempHazard(t)
190 311 local tr = user:species().tempRange.survivable
191 312 if hz == 'cold' then