init.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. local FREQ_BIAS = -.6
  2. local FREQ_SCALE = 3
  3. local SPEED = .02
  4. local fns = {
  5. on_strike = {},
  6. freq_bias = {},
  7. intens_bias = {},
  8. heat_bias = {},
  9. humidity_bias = {},
  10. }
  11. storms = {
  12. }
  13. local perlins = {}
  14. local sounds = {
  15. thunder = {
  16. "storms_thunder_01_ccby_hantorio",
  17. "storms_thunder_01_ccby_hantorio",
  18. -- "storms_thunder_02_PD",
  19. "storms_thunder_03_PD",
  20. },
  21. }
  22. local function color_lerp(a, b, x)
  23. local x1 = 1.0 - x
  24. return {
  25. r = a.r * x1 + b.r * x,
  26. g = a.g * x1 + b.g * x,
  27. b = a.b * x1 + b.b * x,
  28. -- a = a.a * x1 + b.a * x,
  29. }
  30. end
  31. storms.register_on_lightning_strike = function(fn)
  32. table.insert(fns.on_strike, fn)
  33. end
  34. storms.register_freq_bias = function(fn)
  35. table.insert(fns.freq_bias, fn)
  36. end
  37. storms.register_intensity_bias = function(fn)
  38. table.insert(fns.intens_bias, fn)
  39. end
  40. storms.register_heat_bias = function(fn)
  41. table.insert(fns.heat_bias, fn)
  42. end
  43. storms.register_humidity_bias = function(fn)
  44. table.insert(fns.humidty_bias, fn)
  45. end
  46. local function get_intens_bias(pos, orig_intens, player)
  47. local bias = 0
  48. for _,fn in ipairs(fns.intens_bias) do
  49. bias = bias + fn(pos, orig_intens, player)
  50. end
  51. return bias
  52. end
  53. local function get_freq_bias(pos, orig_freq, player)
  54. local bias = 0
  55. for _,fn in ipairs(fns.freq_bias) do
  56. bias = bias + fn(pos, orig_freq, player)
  57. end
  58. return bias
  59. end
  60. local function get_heat_bias(pos, orig)
  61. local bias = 0
  62. for _,fn in ipairs(fns.heat_bias) do
  63. bias = bias + fn(pos, orig)
  64. end
  65. return bias
  66. end
  67. local function get_humidity_bias(pos, orig)
  68. local bias = 0
  69. for _,fn in ipairs(fns.humidity_bias) do
  70. bias = bias + fn(pos, orig)
  71. end
  72. return bias
  73. end
  74. local on = false
  75. local storm_players = {}
  76. local good_biomes = {}
  77. for _,def in pairs(minetest.registered_biomes) do
  78. if def.y_max >= 10 and def.y_min <= 10 then
  79. table.insert(good_biomes, def)
  80. end
  81. end
  82. local function get_noise(pos)
  83. return heat_noise:get2d({x=pos.x, y=pos.z}), humidity_noise:get2d({x=pos.x, y=pos.z})
  84. end
  85. local function find_biome(he, hu)
  86. local smallest = 99999999999
  87. local tmp = nil
  88. for _,def in pairs(good_biomes) do
  89. local a = he - def.heat_point
  90. local b = hu - def.humidity_point
  91. local c = math.sqrt(a*a + b*b)
  92. if c < smallest then
  93. smallest = c
  94. tmp = def
  95. end
  96. end
  97. return tmp.name
  98. end
  99. local function get_biome(pos)
  100. local he, hu = get_noise(pos)
  101. he = he + get_heat_bias(pos, he)
  102. hu = hu + get_humidity_bias(pos, hu)
  103. return find_biome(he, hu)
  104. end
  105. minetest.after(0, function()
  106. local noise = minetest.get_mapgen_setting_noiseparams("mg_biome_np_heat")
  107. heat_noise = minetest.get_perlin(noise)
  108. noise = minetest.get_mapgen_setting_noiseparams("mg_biome_np_humidity")
  109. humidity_noise = minetest.get_perlin(noise)
  110. end)
  111. local function randompos(center, dist)
  112. return {
  113. x = center.x + math.random(-dist, dist),
  114. y = center.y,
  115. z = center.z + math.random(-dist, dist),
  116. }
  117. end
  118. local function pcopy(p)
  119. return {x=p.x, y=p.y, z=p.z}
  120. end
  121. local function do_lightning(cloudh, pos)
  122. local h = cloudh - 10
  123. while h > -15 do
  124. minetest.add_particle({
  125. pos = {x=pos.x, y=h, z=pos.z},
  126. velocity = {x=0, y=0, z=0},
  127. acceleration = {x=0, y=0, z=0},
  128. expirationtime = .1,
  129. size = 300,
  130. collisiondetection = false,
  131. vertical = true,
  132. texture = "storms_lightning.png",
  133. playername = "singleplayer"
  134. })
  135. h = h - 30
  136. end
  137. local p = {x=pos.x, y=cloudh, z=pos.z}
  138. while p.y >= -1 do
  139. local n = minetest.get_node(p)
  140. if n.name ~= "air" and n.name ~= "ignore" then
  141. -- node callbacks
  142. local def = minetest.registered_nodes[n.name]
  143. if def.on_lightning_strike then
  144. def.on_lightning_strike(pcopy(p))
  145. end
  146. -- global callbacks
  147. for _,fn in pairs(fns.on_strike) do
  148. fn(pcopy(p), n)
  149. end
  150. break
  151. end
  152. p.y = p.y - 1
  153. end
  154. minetest.sound_play(sounds.thunder[math.random(#sounds.thunder)], {
  155. pos = p,
  156. max_hear_distance = 100,
  157. gain = 5.0,
  158. })
  159. end
  160. local function spawn_blizzard(pos, vel, sz)
  161. local ht = 7
  162. minetest.add_particlespawner({
  163. amount = 4000,
  164. time = 5,
  165. minpos = vector.add({x=pos.x-sz, y=pos.y-ht, z=pos.z-sz}, vector.multiply(vel, -.95)),
  166. maxpos = vector.add({x=pos.x+sz, y=pos.y+ht, z=pos.z+sz}, vector.multiply(vel, -.95)),
  167. minvel = vector.add(vel, {x=-1, y=0, z=-1}),
  168. maxvel = vector.add(vel, {x=5, y=0.5, z=5}),
  169. minacc = {x=-01.1, y=0.1, z=-01.1},
  170. maxacc = {x=01.1, y=01.3, z=01.1},
  171. minexptime = 1.5,
  172. maxexptime = 2.5,
  173. collisiondetection = true,
  174. collision_removal = true,
  175. minsize = 40,
  176. maxsize = 45,
  177. texture = "storms_snow.png",
  178. })
  179. end
  180. local function spawn_sandstorm(pos, vel, sz, lvl)
  181. local ht = 7
  182. minetest.add_particlespawner({
  183. amount = lvl * 5000,
  184. time = 5,
  185. minpos = vector.add({x=pos.x-sz, y=pos.y-ht, z=pos.z-sz}, vector.multiply(vel, -.95)),
  186. maxpos = vector.add({x=pos.x+sz, y=pos.y+ht, z=pos.z+sz}, vector.multiply(vel, -.95)),
  187. minvel = vector.add(vel, {x=-1, y=0, z=-1}),
  188. maxvel = vector.add(vel, {x=5, y=0.5, z=5}),
  189. minacc = {x=-01.1, y=0.1, z=-01.1},
  190. maxacc = {x=01.1, y=01.3, z=01.1},
  191. minexptime = 1.5,
  192. maxexptime = 2.5,
  193. collisiondetection = true,
  194. collision_removal = true,
  195. minsize = 40,
  196. maxsize = 45,
  197. texture = "storms_dust.png",
  198. })
  199. end
  200. local function spawn_rainclouds(pos, vel, sz, lvl)
  201. local offht = 60
  202. local ht = 10
  203. minetest.add_particlespawner({
  204. amount = lvl * 5000,
  205. time = 5,
  206. minpos = {x=pos.x-sz, y=pos.y+offht, z=pos.z-sz},
  207. maxpos = {x=pos.x+sz, y=pos.y+offht+ht, z=pos.z+sz},
  208. minvel = vector.add(vel, {x=-1, y=0, z=-1}),
  209. maxvel = vector.add(vel, {x=5, y=0.5, z=5}),
  210. minacc = {x=-0.1, y=0.1, z=-0.1},
  211. maxacc = {x=0.1, y=0.3, z=0.1},
  212. minexptime = 2,
  213. maxexptime = 7,
  214. minsize = 300,
  215. maxsize = 400,
  216. texture = "storms_cloud.png^[colorize:black:120",
  217. })
  218. end
  219. local function spawn_rain(pos, vel, sz, lvl)
  220. local offht = 10
  221. local ht = 10
  222. minetest.add_particlespawner({
  223. amount = lvl * 1000,
  224. time = 5,
  225. minpos = {x=pos.x-sz, y=pos.y+offht, z=pos.z-sz},
  226. maxpos = {x=pos.x+sz, y=pos.y+offht+ht, z=pos.z+sz},
  227. minvel = {x=vel.x, y=-40, z=vel.z},
  228. maxvel = {x=vel.x, y=-40, z=vel.z},
  229. minacc = {x=-0.1, y=0.1, z=-0.1},
  230. maxacc = {x=0.1, y=0.3, z=0.1},
  231. collisiondetection = true,
  232. collision_removal = true,
  233. minexptime = 2,
  234. maxexptime = 7,
  235. minsize = 10,
  236. maxsize = 15,
  237. texture = "storms_raindrop.png",
  238. })
  239. end
  240. local function spawn_snow(pos, vel, sz, lvl)
  241. local offht = 10
  242. local ht = 10
  243. minetest.add_particlespawner({
  244. amount = lvl * 1000,
  245. time = 5,
  246. minpos = {x=pos.x-sz, y=pos.y+offht, z=pos.z-sz},
  247. maxpos = {x=pos.x+sz, y=pos.y+offht+ht, z=pos.z+sz},
  248. minvel = {x=vel.x, y=-20, z=vel.z},
  249. maxvel = {x=vel.x, y=-20, z=vel.z},
  250. minacc = {x=-0.1, y=0.1, z=-0.1},
  251. maxacc = {x=0.1, y=0.3, z=0.1},
  252. collisiondetection = true,
  253. collision_removal = true,
  254. minexptime = 2,
  255. maxexptime = 7,
  256. minsize = 10,
  257. maxsize = 15,
  258. texture = "storms_snowflake.png",
  259. })
  260. end
  261. local function spawn_lightning(pos, amount, sz)
  262. local offht = 60
  263. for i = 1,math.random(amount) do
  264. minetest.after(math.random(5), function()
  265. do_lightning(pos.y+60, randompos(pos, sz))
  266. end)
  267. end
  268. end
  269. local biome_skies = {
  270. ["tundra"] = {color = {r=255, g=255, b=255}, clouds = false},
  271. ["taiga"] = {color = {r=255, g=255, b=255}, clouds = false},
  272. ["snowy_grassland"] = {color = {r=255, g=255, b=255}, clouds = false},
  273. ["cold_desert"] = {color = {r=255, g=255, b=255}, clouds = false},
  274. ["desert"] = {color = {r=130, g=105, b=25}, clouds = false},
  275. ["sandstone_desert"] = {color = {r=130, g=105, b=25}, clouds = false},
  276. ["grassland"] = {color = {r=20, g=20, b=30}, clouds = false},
  277. ["deciduous_forest"] = {color = {r=20, g=20, b=30}, clouds = false},
  278. ["coniferous_forest"] = {color = {r=20, g=20, b=30}, clouds = false},
  279. ["savanna"] = {color = {r=20, g=20, b=30}, clouds = false},
  280. ["rainforest"] = {color = {r=20, g=20, b=30}, clouds = false},
  281. }
  282. local biome_spawners = {}
  283. biome_spawners.tundra = function(pos, dir, lvl)
  284. spawn_blizzard(pos, dir, 15, lvl)
  285. end
  286. biome_spawners.taiga = function(pos, dir, lvl)
  287. spawn_snow(pos, {x=0, y=0, z=0}, 20, lvl)
  288. end
  289. biome_spawners.grassland = function(pos, dir, lvl)
  290. spawn_rainclouds(pos, dir, 200, lvl)
  291. spawn_rain(pos, {x=0, y=0, z=0}, 20, lvl)
  292. spawn_lightning(pos, 15 * lvl, 60)
  293. end
  294. biome_spawners.snowy_grassland = function(pos, dir, lvl)
  295. spawn_blizzard(pos, dir, 15, lvl)
  296. end
  297. biome_spawners.savanna = function(pos, dir, lvl)
  298. spawn_rainclouds(pos, dir, 200, lvl)
  299. -- spawn_rain(pos, {x=0, y=0, z=0}, 10)
  300. spawn_lightning(pos, 30 * lvl, 70)
  301. end
  302. biome_spawners.deciduous_forest = function(pos, dir, lvl)
  303. spawn_rainclouds(pos, dir, 200, lvl)
  304. spawn_rain(pos, {x=0, y=0, z=0}, 20, lvl)
  305. end
  306. biome_spawners.rainforest = function(pos, dir, lvl)
  307. spawn_rainclouds(pos, dir, 200, lvl)
  308. spawn_rain(pos, {x=0, y=0, z=0}, 20, lvl)
  309. end
  310. biome_spawners.coniferous_forest = function(pos, dir, lvl)
  311. spawn_rainclouds(pos, dir, 200, lvl)
  312. spawn_rain(pos, {x=0, y=0, z=0}, 20, lvl)
  313. end
  314. biome_spawners.cold_desert = function(pos, dir, lvl)
  315. spawn_blizzard(pos, dir, 15, lvl)
  316. end
  317. biome_spawners.desert = function(pos, dir, lvl)
  318. spawn_sandstorm(pos, dir, 15, lvl)
  319. end
  320. biome_spawners.sandstone_desert = function(pos, dir, lvl)
  321. spawn_sandstorm(pos, dir, 15, lvl)
  322. end
  323. local function set_biome_storm_sky(pinfo, b1, b2, n_biome, n_normal)
  324. local sky1 = biome_skies[b1]
  325. local sky2 = biome_skies[b2]
  326. if not sky1 then
  327. print("missing biome: ".. b1)
  328. return
  329. end
  330. if not sky2 then
  331. print("missing biome: ".. b2)
  332. return
  333. end
  334. local color = color_lerp(sky1.color, sky2.color, n_biome)
  335. color = color_lerp(color, pinfo.default_sky.color, n_normal)
  336. local sky
  337. if n_normal > .75 then
  338. sky = pinfo.default_sky
  339. elseif n_biome > .5 then
  340. sky = sky2
  341. else
  342. sky = sky1
  343. end
  344. pinfo.player:set_sky(color, sky.type or "plain", sky.tex, sky.clouds or false)
  345. end
  346. minetest.register_craftitem("storms:rainstick", {
  347. description = "Magic Rainstick",
  348. inventory_image = "default_stick.png^[colorize:gold:80",
  349. stack_max = 1,
  350. on_use = function(itemstack, player, pointed_thing)
  351. if sky_defaults == nil then
  352. sky_defaults = {}
  353. sky_defaults.col, sky_defaults.tp, sky_defaults.tex, sky_defaults.cl = player:get_sky()
  354. end
  355. if on then
  356. on = false
  357. player:set_sky(sky_defaults.col, sky_defaults.tp, sky_defaults.tex, sky_defaults.cl)
  358. else
  359. on = true
  360. local function spawn_storm()
  361. local pos = player:get_pos()
  362. local biome = get_biome(pos)
  363. local fn = biome_spawners[biome]
  364. if not fn then
  365. print("missing spawner biome: "..biome)
  366. end
  367. fn(pos, {x=20, y=0, x=10}, 1)
  368. -- set_biome_storm_sky(player, biome)
  369. if on then
  370. minetest.after(5, function()
  371. spawn_storm()
  372. end)
  373. end
  374. end
  375. spawn_storm()
  376. player:set_sky({r=20, g=20, b=30}, "plain", nil, false)
  377. end
  378. end,
  379. })
  380. storms.register_on_lightning_strike(function(pos)
  381. -- pos.y = pos.y + 1
  382. -- minetest.set_node(pos, {name="fire:basic_flame"})
  383. end)
  384. local function get_player_sky(player)
  385. local sky = {}
  386. sky.color, sky.type, sky.tex, sky.clouds = player:get_sky()
  387. return sky
  388. end
  389. minetest.register_on_joinplayer(function(player)
  390. local name = player:get_player_name()
  391. storm_players[name] = {
  392. a = nil,
  393. b = nil,
  394. fill = 1,
  395. player = player,
  396. default_sky = get_player_sky(player),
  397. }
  398. print(dump(storm_players[name].default_sky))
  399. end)
  400. minetest.register_on_leaveplayer(function(player)
  401. local name = player:get_player_name()
  402. storm_players[name] = nil
  403. end)
  404. local function activate_storm(player )
  405. local pos = player:get_pos()
  406. local biome = get_biome(pos)
  407. local fn = biome_spawners[biome]
  408. if not fn then
  409. print("missing spawner biome: "..biome)
  410. end
  411. fn(pos)
  412. end
  413. local function clamp(min, max, n)
  414. if n < min then return min end
  415. if n > max then return max end
  416. return n
  417. end
  418. local function storm_loop()
  419. local time = minetest.get_gametime()
  420. for name,pinfo in pairs(storm_players) do
  421. local pos = pinfo.player:get_pos()
  422. local t = math.sin(time / (5 * 2 * math.pi))
  423. local t2 = math.cos(time / (7 * 2 * math.pi))
  424. local p1 = {
  425. x = ((t * 20 + t2 * 30 + pos.x + time) % 65536) - 32768,
  426. y = 0,
  427. z = ((t * 20 + t2 * 30 + pos.z + time) % 65536) - 32768,
  428. }
  429. local dx = perlins.dx:get2dMap_flat(p1)[1]
  430. local dz = perlins.dz:get2dMap_flat(p1)[1]
  431. -- for i = 1,2000,3 do
  432. -- local f3 = perlins.freq3:get3dMap_flat({x=pos.x, y=pos.z, z=i --[[(time *20) % 2000]]})[1]
  433. -- f3 = (f3 * 4) - 1.6
  434. -- print("perlin: ".. dump(f3))
  435. -- end
  436. local f3 = perlins.freq3:get3dMap_flat({x=pos.x, y=pos.z, z=(time * SPEED) % 65536})[1]
  437. f3 = (f3 * FREQ_SCALE) + FREQ_BIAS -- - 1.6
  438. -- print("perlin: ".. dump(f3))
  439. f3 = f3 + get_freq_bias(pos, f3, pinfo.player)
  440. local biome = get_biome(pos)
  441. -- f3 = nil
  442. -- print("storm intensity: ".. f .. " ("..f1..", "..f2..")")
  443. local intens = f3 + get_intens_bias(pos, f3, pinfo.player)
  444. if f3 > 0 then
  445. local dir = {x = dx, y = 0, z = dz}
  446. local fn = biome_spawners[biome]
  447. if not fn then
  448. print("missing spawner biome: "..biome)
  449. end
  450. fn(pos, dir, 1, intens)
  451. end
  452. set_biome_storm_sky(pinfo, biome, biome, 1, clamp(0, 1, 1-intens))
  453. end
  454. minetest.after(5, storm_loop)
  455. end
  456. minetest.after(2, function()
  457. perlins.dx = minetest.get_perlin_map({
  458. flags = {eased = false},
  459. lacunarity = 4,
  460. octaves = 4,
  461. offset = 0,
  462. persistence = 0.65,
  463. seed = 35363,
  464. scale = 10,
  465. spread = {x=1000, y=1000, z=1000}
  466. }, {x=1,y=1,z=1})
  467. perlins.dz = minetest.get_perlin_map({
  468. flags = {eased = false},
  469. lacunarity = 4,
  470. octaves = 4,
  471. offset = 0,
  472. persistence = 0.65,
  473. seed = 678786,
  474. scale = 10,
  475. spread = {x=1000, y=1000, z=1000}
  476. }, {x=1,y=1,z=1})
  477. --[[
  478. perlins.freq1 = minetest.get_perlin_map({
  479. flags = {eased = false},
  480. lacunarity = 2,
  481. octaves = 3,
  482. offset = 0,
  483. persistence = 0.25,
  484. seed = 79932,
  485. scale = 1,
  486. spread = {x=2000, y=2000, z=2000}
  487. }, {x=1,y=1,z=1})
  488. perlins.freq2 = minetest.get_perlin_map({
  489. flags = {eased = false},
  490. lacunarity = 2,
  491. octaves = 1,
  492. offset = 0,
  493. persistence = 0.25,
  494. seed = 6445,
  495. scale = 1,
  496. spread = {x=2000, y=2000, z=2000}
  497. }, {x=1,y=1,z=1})
  498. ]]
  499. perlins.freq3 = minetest.get_perlin_map({
  500. flags = {eased = false},
  501. lacunarity = 4,
  502. octaves = 5,
  503. offset = 0,
  504. persistence = 0.45,
  505. seed = 179334,
  506. scale = 1,
  507. spread = {x=500, y=500, z=500}
  508. }, {x=2,y=2,z=2})
  509. storm_loop()
  510. end)