initial commit

master
Arturas Norkus 2017-03-05 18:19:44 +02:00
parent 81e265c7a3
commit 7a3648b7d9
14 changed files with 496 additions and 1 deletions

View File

@ -1 +1,40 @@
# happy_weather
Happy Weather
=======================
A weather mod for Minetest (http://minetest.net/)
Weathers included
-----------------------
* light rain
* heavy rain
* thunder
Commands
-----------------------
* `start_weather <weather code>` requires `weather_manager` privilege.
* `stop_weather <weather code>` requires `weather_manager` privilege.
Dependencies
-----------------------
* [happy_weather_api](https://github.com/xeranas/happy_weather_api) mod-api (used to manage weathers)
* [skycolor](https://github.com/xeranas/skycolor) mod-api (used to manage sky color)
* [lightning](https://github.com/minetest-mods/lightning) mod (used by thunder weather).
License of source code:
-----------------------
MIT
Authors of media files:
-----------------------
xeranas:
* `happy_weather_heavy_rain_drops.png` - CC-0
* `happy_weather_light_rain_raindrop_1.png` - CC-0
* `happy_weather_light_rain_raindrop_2.png` - CC-0
* `happy_weather_light_rain_raindrop_3.png` - CC-0
inchadney (http://freesound.org/people/inchadney/):
* `light_rain_drop.ogg` - CC-0 (http://freesound.org/people/rcproductions54/sounds/265045/)
* `heavy_rain_drop.ogg` - CC-BY-SA 3.0 (cut from http://freesound.org/people/inchadney/sounds/58835/)

3
depends.txt Normal file
View File

@ -0,0 +1,3 @@
happy_weather_api
skycolor
lightning

157
heavy_rain.lua Normal file
View File

@ -0,0 +1,157 @@
--
-- Happy Weather: Heavy Rain
-- License: MIT
-- Credits:
-- * xeranas
local heavy_rain = {}
-- Weather identification code
heavy_rain.code = "heavy_rain"
-- Keeps sound handler references
local sound_handlers = {}
-- Manual triggers flags
local manual_trigger_start = false
local manual_trigger_end = false
-- Skycolor layer id
local SKYCOLOR_LAYER = "happy_weather_heavy_rain_sky"
heavy_rain.about_to_start = function(dtime)
if manual_trigger_start then
manual_trigger_start = false
return true
end
return false
end
heavy_rain.about_to_end = function(dtime)
if manual_trigger_end then
manual_trigger_end = false
return true
end
return false
end
local set_sky_box = function()
skycolor.add_layer(
SKYCOLOR_LAYER,
{{r=0, g=0, b=0},
{r=65, g=66, b=78},
{r=112, g=110, b=119},
{r=65, g=66, b=78},
{r=0, g=0, b=0}})
skycolor.active = true
end
local set_rain_sound = function(player)
return minetest.sound_play("heavy_rain_drop", {
object = player,
max_hear_distance = 2,
loop = true,
})
end
local remove_rain_sound = function(player)
local sound = sound_handlers[player:get_player_name()]
if sound ~= nil then
minetest.sound_stop(sound)
sound_handlers[player:get_player_name()] = nil
end
end
heavy_rain.setup = function(player)
sound_handlers[player:get_player_name()] = set_rain_sound(player)
set_sky_box()
end
heavy_rain.clear_up = function(player)
remove_rain_sound(player)
skycolor.remove_layer(SKYCOLOR_LAYER)
end
local rain_drop_texture = "happy_weather_heavy_rain_drops.png"
local add_close_range_rain_particle = function(player)
local offset = {
front = 1,
back = 0,
top = 2
}
local random_pos = utils.get_random_pos(player, offset)
local offset_y = -1 -- rain drop visual size / 2 + player size / 2
if utils.is_outdoor(random_pos, offset_y) then
minetest.add_particle({
pos = {x=random_pos.x, y=random_pos.y, z=random_pos.z},
velocity = {x=0, y=-10, z=0},
acceleration = {x=0, y=-10, z=0},
expirationtime = 5,
size = 30,
collisiondetection = true,
collision_removal = true,
vertical = true,
texture = rain_drop_texture,
playername = player:get_player_name()
})
end
end
local add_wide_range_rain_particle = function(player)
local offset = {
front = 10,
back = 5,
top = 8
}
local random_pos = utils.get_random_pos(player, offset)
if utils.is_outdoor(random_pos) then
minetest.add_particle({
pos = {x=random_pos.x, y=random_pos.y, z=random_pos.z},
velocity = {x=0, y=-10, z=0},
acceleration = {x=0, y=-30, z=0},
expirationtime = 5,
size = 30,
collisiondetection = true,
collision_removal = true,
vertical = true,
texture = rain_drop_texture,
playername = player:get_player_name()
})
end
end
local display_rain_particles = function(player)
if utils.is_underwater(player) then
return
end
add_close_range_rain_particle(player)
local particles_number_per_update = 5
for i=particles_number_per_update, 1,-1 do
add_wide_range_rain_particle(player)
end
end
heavy_rain.update = function(dtime, player)
display_rain_particles(player)
end
heavy_rain.manual_trigger_start = function()
manual_trigger_start = true
end
heavy_rain.manual_trigger_end = function()
manual_trigger_end = true
end
happy_weather.register_weather(heavy_rain)

9
init.lua Normal file
View File

@ -0,0 +1,9 @@
local modpath = minetest.get_modpath("happy_weather");
-- Utilities / Helpers
dofile(modpath.."/utils.lua")
-- Weathers
dofile(modpath.."/light_rain.lua")
dofile(modpath.."/heavy_rain.lua")
dofile(modpath.."/thunder.lua")

139
light_rain.lua Normal file
View File

@ -0,0 +1,139 @@
--
-- Happy Weather: Light Rain
-- License: MIT
-- Credits:
-- * xeranas
local light_rain = {}
-- Weather identification code
light_rain.code = "light_rain"
-- Keeps sound handler references
local sound_handlers = {}
-- Manual triggers flags
local manual_trigger_start = false
local manual_trigger_end = false
-- Skycolor layer id
local SKYCOLOR_LAYER = "happy_weather_light_rain_sky"
light_rain.about_to_start = function(dtime)
if manual_trigger_start then
manual_trigger_start = false
return true
end
return false
end
light_rain.about_to_end = function(dtime)
if manual_trigger_end then
manual_trigger_end = false
return true
end
return false
end
local set_sky_box = function()
skycolor.add_layer(
SKYCOLOR_LAYER,
{{r=0, g=0, b=0},
{r=85, g=86, b=98},
{r=152, g=150, b=159},
{r=85, g=86, b=98},
{r=0, g=0, b=0}})
skycolor.active = true
end
local set_rain_sound = function(player)
return minetest.sound_play("light_rain_drop", {
object = player,
max_hear_distance = 2,
loop = true,
})
end
local remove_rain_sound = function(player)
local sound = sound_handlers[player:get_player_name()]
if sound ~= nil then
minetest.sound_stop(sound)
sound_handlers[player:get_player_name()] = nil
end
end
light_rain.setup = function(player)
sound_handlers[player:get_player_name()] = set_rain_sound(player)
set_sky_box()
end
light_rain.clear_up = function(player)
remove_rain_sound(player)
skycolor.remove_layer(SKYCOLOR_LAYER)
end
-- Random texture getter
local choice_random_rain_drop_texture = function()
local texture_name
local random_number = math.random()
if random_number > 0.33 then
texture_name = "happy_weather_light_rain_raindrop_1.png"
elseif random_number > 0.66 then
texture_name = "happy_weather_light_rain_raindrop_2.png"
else
texture_name = "happy_weather_light_rain_raindrop_3.png"
end
return texture_name;
end
local add_rain_particle = function(player)
local offset = {
front = 5,
back = 2,
top = 4
}
local random_pos = utils.get_random_pos(player, offset)
if utils.is_outdoor(random_pos) then
minetest.add_particle({
pos = {x=random_pos.x, y=random_pos.y, z=random_pos.z},
velocity = {x=0, y=-10, z=0},
acceleration = {x=0, y=-30, z=0},
expirationtime = 2,
size = math.random(0.5, 3),
collisiondetection = true,
collision_removal = true,
vertical = true,
texture = choice_random_rain_drop_texture(),
playername = player:get_player_name()
})
end
end
local display_rain_particles = function(player)
if utils.is_underwater(player) then
return
end
add_rain_particle(player)
end
light_rain.update = function(dtime, player)
display_rain_particles(player)
end
light_rain.manual_trigger_start = function()
manual_trigger_start = true
end
light_rain.manual_trigger_end = function()
manual_trigger_end = true
end
happy_weather.register_weather(light_rain)

1
mod.conf Normal file
View File

@ -0,0 +1 @@
name = happy_weather

BIN
sounds/heavy_rain_drop.ogg Normal file

Binary file not shown.

BIN
sounds/light_rain_drop.ogg Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

87
thunder.lua Normal file
View File

@ -0,0 +1,87 @@
-- Turn off lightning mod 'auto mode'
lightning.auto = false
local thunder = {}
-- Weather identification code
thunder.code = "thunder"
local thunder_target_weather_code = "heavy_rain"
--
-- Happy Weather: Thunder
-- License: MIT
-- Credits:
-- * xeranas
-- Manual triggers flags
local manual_trigger_start = false
local manual_trigger_end = false
-- Thunder weather appearance control
local thunder_weather_chance = 5 -- 5 percent appearance during heavy rain
local thunder_weather_next_check = 0
local thunder_weather_check_delay = 600 -- to avoid checks continuously
thunder.about_to_start = function(dtime)
if manual_trigger_start then
manual_trigger_start = false
return true
end
if thunder_weather_next_check > os.time() then
return
end
if happy_weather.is_weather_active(thunder_target_weather_code) then
local random_roll = math.random(0,100)
thunder_weather_next_check = os.time() + thunder_weather_check_delay
if random_roll <= thunder_weather_chance then
return true
end
end
return false
end
thunder.about_to_end = function(dtime)
if manual_trigger_end then
manual_trigger_end = false
return true
end
if happy_weather.is_weather_active(thunder_target_weather_code) == false then
return true
end
return false
end
local calculate_thunder_strike_delay = function()
local delay = math.random(thunder.min_delay, thunder.max_delay)
thunder.next_strike = os.time() + delay
end
thunder.setup = function(dtime)
checked = false
thunder.next_strike = 0
thunder.min_delay = 5
thunder.max_delay = math.random(5, 45)
end
thunder.update = function(dtime, player)
if thunder.next_strike <= os.time() then
lightning.strike()
calculate_thunder_strike_delay()
end
end
thunder.manual_trigger_start = function()
manual_trigger_start = true
end
thunder.manual_trigger_end = function()
manual_trigger_end = true
end
happy_weather.register_weather(thunder)

60
utils.lua Normal file
View File

@ -0,0 +1,60 @@
utils = {}
-- outdoor check based on node light level
utils.is_outdoor = function(pos, offset_y)
if offset_y == nil then
offset_y = 0
end
if minetest.get_node_light({x=pos.x, y=pos.y + offset_y, z=pos.z}, 0.5) == 15 then
return true
end
return false
end
-- checks if player is undewater. This is needed in order to
-- turn off weather particles generation.
utils.is_underwater = function(player)
local ppos = player:getpos()
local offset = player:get_eye_offset()
local player_eye_pos = {x = ppos.x + offset.x,
y = ppos.y + offset.y + 1.5,
z = ppos.z + offset.z}
local node_level = minetest.get_node_level(player_eye_pos)
if node_level == 8 or node_level == 7 then
return true
end
return false
end
-- trying to locate position for particles by player look direction for performance reason.
-- it is costly to generate many particles around player so goal is focus mainly on front view.
utils.get_random_pos = function(player, offset)
local look_dir = player:get_look_dir()
local player_pos = player:getpos()
local random_pos_x = 0
local random_pos_y = 0
local random_pos_z = 0
if look_dir.x > 0 then
if look_dir.z > 0 then
random_pos_x = math.random(player_pos.x - offset.back, player_pos.x + offset.front)
random_pos_z = math.random(player_pos.z - offset.back, player_pos.z + offset.front)
else
random_pos_x = math.random(player_pos.x - offset.back, player_pos.x + offset.front)
random_pos_z = math.random(player_pos.z - offset.front, player_pos.z + offset.back)
end
else
if look_dir.z > 0 then
random_pos_x = math.random(player_pos.x - offset.front, player_pos.x + offset.back)
random_pos_z = math.random(player_pos.z - offset.back, player_pos.z + offset.front)
else
random_pos_x = math.random(player_pos.x - offset.front, player_pos.x + offset.back)
random_pos_z = math.random(player_pos.z - offset.front, player_pos.z + offset.back)
end
end
random_pos_y = player_pos.y + offset.top
return {x=random_pos_x, y=random_pos_y, z=random_pos_z}
end