mirror of
https://github.com/t-affeldt/climate_api.git
synced 2024-12-22 00:40:37 +01:00
Make wind dependent on height, add additional control commands, improve docu
This commit is contained in:
parent
f42b4183e5
commit
d4e00db432
22
README.md
22
README.md
@ -18,7 +18,7 @@ If you notice __odd movement speeds__ or jump heights of players, you should che
|
||||
|
||||
Mods that __modify the sky__ (including skybox, moon, sun, stars and clouds) are sadly not fully compatible because they conflict with Climate API's sky system. You should deactivate the sky features in either mod. You can do this here using the ``Override the skybox`` setting. If you're a mod maker then you can also optionally depend on climate_api and use ``climate_api.skybox.add_layer(playername, layer_name, options)`` to register your skybox change in a compatible way. Note that you need __at least Minetest v5.2.0__ for skybox changes to have any effect.
|
||||
|
||||
Conflicting skybox changes include the ``weather`` mod included in vanilla __Minetest Game__. You will want to disable that mod in order to use the more advanced cloud system introduced by Climate API. Head to ``Settings → All Settings → Games → Minetest Game`` and set ``Enable weather`` to ``Disabled``. This setting will only exist if you are using Minetest Game v5.2.0 or higher.
|
||||
__Important__: Conflicting skybox changes include the ``weather`` mod included in vanilla __Minetest Game__. You will want to disable that mod in order to use the more advanced cloud system introduced by Climate API. Head to ``Settings → All Settings → Games → Minetest Game`` and set ``Enable weather`` to ``Disabled``. This setting will only exist if you are using Minetest Game v5.2.0 or higher.
|
||||
|
||||
The following mods have been created specifically with Climate API in mind:
|
||||
- [Regional Weather](https://github.com/t-affeldt/regional_weather): My own weather pack for climate based weather effects
|
||||
@ -33,10 +33,12 @@ The following mods complement Climate API particularly well:
|
||||
- ``/weather``: Display information on current weather effects. This command will show you current temperature and humidity, active weather presets and currently playing effects
|
||||
- ``/weather_settings``: Display current mod configuration in the chat
|
||||
- ``/weather_influences``: Display all different factors and how they affect you in this moment.
|
||||
- ``/weather_status``: Display a list of all installed weather presets and whether they have been forced on, turned off, or are running normally (auto).
|
||||
- ``/weather_status``: Display a list of all installed weather presets and whether they have been forced on, turned off, or are running normally (auto). If no weather presets are listed here then you need to install a weather mod like Regional Weather.
|
||||
- ``/grant <playername> weather``: Enable a specified player to modify the current weather.
|
||||
- ``/set_heat <value>``: Override the base heat value used to calculate local climate. Positive numbers will increase temperature by X degrees Fahrenheit, whereas negative values will lower it.
|
||||
- ``/set_humidity <value>``: Override the base humidity value used to calculate local climate. Positive numbers will increase humidity by X percent, whereas negative values will lower it.
|
||||
- ``/set_heat <value>``: Override global heat levels with given value.
|
||||
- ``/set_base_heat <value>``: Override the base heat value used to calculate local climate. Positive numbers will increase temperature by X degrees Fahrenheit, whereas negative values will lower it.
|
||||
- ``/set_humidity <value>``: Override global humidity levels with given value.
|
||||
- ``/set_base_humidity <value>``: Override the base humidity value used to calculate local climate. Positive numbers will increase humidity by X percent, whereas negative values will lower it.
|
||||
- ``/set_wind <x> <z>``: Override wind speed and direction. Higher absolute values result in stronger wind. The sign indicates direction.
|
||||
- ``/set_weather <weather> <on|off|auto>``: Set a weather preset to always be applied (on), disable it completely (off), or reset it to be applied automatically (auto). Turning presets on manually might result in partially missing effects (like no sound if you enable sandstorms but no storms). Use ``/weather_status`` for a full list of installed weather presets. The prefix is important.
|
||||
|
||||
@ -51,7 +53,7 @@ This value regulates how often weather presets are recalculated.
|
||||
Higher values will result in smoother transitions between effects as well as faster response times to traveling players.
|
||||
Lower values will significantly increase overall performance at the cost of rougher looking effects.
|
||||
- ``Multiplicator for used particles`` (default 1.0):
|
||||
This value regulated how many particles will be spawned.
|
||||
This value regulates how many particles will be spawned.
|
||||
A value of 1 will use the recommended amount of particles.
|
||||
Lower values can possible increase performance.
|
||||
- ``Dynamically modify nodes`` (default true):
|
||||
@ -91,16 +93,18 @@ A value of 2 will double the speed at which weather presets change.
|
||||
A value of 0.5 will half the speed respectively.
|
||||
|
||||
### Preferences
|
||||
- ``Show degrees in Fahrenheit instead of Celsius`` (default true):
|
||||
If set to true, temperature information in /weather command will be displayed in Fahrenheit.
|
||||
- ``Show degrees in Fahrenheit instead of Celsius`` (default false):
|
||||
If set to true, temperature information in */weather* command will be displayed in Fahrenheit.
|
||||
- ``Play ambient sound loops`` (default true):
|
||||
If set to true, weather effects are allowed to play sound loops.
|
||||
You can also adjust sound levels instead of deactivating this feature completely.
|
||||
Setting this value to false will be slightly more performant than setting the volume to zero.
|
||||
Note that you can also adjust sound levels instead of deactivating this feature completely.
|
||||
- ``Volume of sound effects`` (default 1.0):
|
||||
This value regulates overall sound volume.
|
||||
A value of 2 will double the volume whereas a value of 0.5 will reduce the volume by half.
|
||||
|
||||
## Modding Information
|
||||
Check the [api_doc.md](https://github.com/t-affeldt/climate_api/blob/master/api_doc.md) for a (currently incomplete) documentation on how to register new weather presets and visual effects. Use my weather [presets](https://github.com/t-affeldt/regional_weather/tree/master/ca_weathers) and [effects](https://github.com/t-affeldt/regional_weather/tree/master/ca_effects) as an example. Ask in the [forum](https://forum.minetest.net/viewtopic.php?t=24569) or open an [issue](https://github.com/t-affeldt/climate_api/issues) if you run into problems. Also check the source code of predefined weather effects because they include usage documentation at the top of each file.
|
||||
|
||||
## License
|
||||
- Source Code: *GNU LGPL v3* by me
|
||||
- Sun and moon textures: *CC BY-SA (3.0)* by Cap
|
||||
|
@ -1,15 +1,11 @@
|
||||
# TODO
|
||||
|
||||
## Planned for first release
|
||||
- Improve value structures of particle effects
|
||||
- Find good values for weather conditions
|
||||
## Needs improvement
|
||||
- Write documentation on how to add weathers and effects
|
||||
|
||||
## Nice to have
|
||||
- Assign meta data (like "downfall", "wind", etc.) to weather presets
|
||||
- Optimize performance by replacing some particles with animated texture planes
|
||||
- Adjust size of particle boxes based on player speed
|
||||
- Generate wind based on speed and yaw instead of x and z values
|
||||
|
||||
## Future Plans & Ideas
|
||||
- Complete season system
|
||||
|
55
api_doc.md
55
api_doc.md
@ -1,7 +1,7 @@
|
||||
# API Documentation
|
||||
|
||||
## How to read this document
|
||||
If a function states multiple parameters of the same name then either of them has to be passed on function call. Look at the function signature to determine the order of required parameters.
|
||||
If a function states multiple parameters of the same name then either of them has to be passed on function call. Look at the function signature to determine the order of required parameters. So far, all parameters are mandatory.
|
||||
|
||||
## Custom Weather Registration
|
||||
|
||||
@ -82,22 +82,29 @@ __Parameter__: ``pos <vector>``: Coordinates of requested location
|
||||
__Returns__: ``<number>`` indicating current humidity
|
||||
|
||||
### Get Current Windspeed
|
||||
``climate_api.environment.get_wind()``
|
||||
``climate_api.environment.get_wind(pos)``
|
||||
|
||||
__Parameter__: ``pos <vector>``: Coordinates of requested location. Right now, only y-coordinate is used.
|
||||
|
||||
__Returns__: ``<vector>`` indicating speed and direction
|
||||
|
||||
### ``climate_api.environment.get_weather_presets(player)``
|
||||
### Get Active Weather Presets
|
||||
``climate_api.environment.get_weather_presets(player)``
|
||||
|
||||
### ``climate_api.environment.get_effects(player)``
|
||||
### Get Active Weather Effects
|
||||
``climate_api.environment.get_effects(player)``
|
||||
|
||||
|
||||
## Skybox Modification
|
||||
|
||||
### ``climate_api.skybox.add(playername, name, sky)``
|
||||
### Add Sky Configuration Layer
|
||||
``climate_api.skybox.add(playername, name, sky)``
|
||||
|
||||
### ``climate_api.skybox.remove(playername, name)``
|
||||
### Remove Sky Configuration Layer
|
||||
``climate_api.skybox.remove(playername, name)``
|
||||
|
||||
### ``climate_api.skybox.update(playername)``
|
||||
### Update Player Sky
|
||||
``climate_api.skybox.update(playername)``
|
||||
|
||||
|
||||
## Player Physics Modifications
|
||||
@ -147,6 +154,36 @@ __Parameters__:
|
||||
|
||||
__Returns__: ``<table>`` consisting of all attributes from A and B.
|
||||
|
||||
### ``climate_api.utility.sigmoid(value, max, growth, midpoint)``
|
||||
### Limit Numeric Boundaries
|
||||
``climate_api.utility.rangelim(value, min, max)``
|
||||
|
||||
### ``climate_api.utility.normalized_cycle(value)``
|
||||
This function will return the specified value if it falls in range between minimum and maximum. Otherwise, it will return the closest boundary.
|
||||
|
||||
__Parameter__:
|
||||
- ``value <number>``: The number to check and return
|
||||
- ``min <number>``: The lower boundary
|
||||
- ``max <number>``: The upper boundary
|
||||
|
||||
__Returns__: ``<number>`` being either the value or the closest boundary
|
||||
|
||||
### Statistical Sigmoid Function
|
||||
``climate_api.utility.sigmoid(value, max, growth, midpoint)``
|
||||
|
||||
This method provides a logistic function that will result in growing return values for greater input values. The resulting function graph will look like an S and fall in range between ``0`` and ``max``. You can adjust the curve by specifying growth rate and midpoint.
|
||||
|
||||
__Parameters__:
|
||||
- ``value <number>``: x value supplied to the function
|
||||
- ``max <number>``: Maximum return value
|
||||
- ``growth <number>``: Logistic growth rate
|
||||
- ``midpoint <number>`` Return value for ``value = 0`` and function midpoint
|
||||
|
||||
__Returns__: ``<number>`` indicating y coordinate of logistic function
|
||||
|
||||
### Normalized Sinus Cycle
|
||||
``climate_api.utility.normalized_cycle(value)``
|
||||
|
||||
This function provides an easy way to generate a simple curve with a maximal turning point of ``y = 1`` located at ``value = 0`` and the lowest points of ``y = 0`` at ``value = +/- 1``.
|
||||
|
||||
__Parameter__: ``value <number>``: The supplied x coordinate
|
||||
|
||||
__Returns__: ``<number>`` indicating resulting y coordinate between ``0`` and ``1``.
|
@ -35,7 +35,7 @@ local function check_hit(player, ray)
|
||||
-- use raycating to factor in wind speed
|
||||
local origin = vector.add(ppos, {x = 0, y = ray.height or 0, z = 0 })
|
||||
if ray.use_wind ~= false then
|
||||
local wind = climate_api.environment.get_wind()
|
||||
local wind = climate_api.environment.get_wind(origin)
|
||||
local velocity = ray.velocity or 1
|
||||
local windpos = vector.multiply(
|
||||
vector.normalize(vector.add({ x = 0, y = -velocity, z = 0 }, wind)),
|
||||
|
@ -22,7 +22,9 @@ local function apply_hud(pname, weather, hud)
|
||||
local file
|
||||
if hud.color_correction then
|
||||
local pos = vector.add(player:get_pos(), {x = 0, y = 1, z = 0})
|
||||
local light = math.floor(math.max(minetest.env:get_node_light(pos) / 15, 0.2) * 256)
|
||||
local node_light = minetest.env:get_node_light(pos)
|
||||
if not node_light then node_light = 0 end
|
||||
local light = math.floor(math.max(node_light / 15, 0.2) * 256)
|
||||
local shadow = 256 - light
|
||||
|
||||
local dark_file = hud.file .. "^[multiply:#000000ff^[opacity:" .. shadow
|
||||
|
@ -175,7 +175,8 @@ local function parse_config(player, particles)
|
||||
|
||||
-- move particles in wind direction
|
||||
if config.use_wind then
|
||||
local wind = climate_api.environment.get_wind()
|
||||
local pos = vector.multiply(vector.add(config.minpos, config.maxpos), 0.5)
|
||||
local wind = climate_api.environment.get_wind(pos)
|
||||
-- adjust velocity to include wind
|
||||
config.minvel = vector.add(config.minvel, wind)
|
||||
config.maxvel = vector.add(config.maxvel, wind)
|
||||
|
@ -41,3 +41,5 @@ end
|
||||
|
||||
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")
|
||||
climate_api.register_effect(EFFECT_NAME, remove_effect, "stop")
|
||||
|
||||
climate_api.set_effect_cycle(EFFECT_NAME, climate_api.SHORT_CYCLE)
|
2
init.lua
2
init.lua
@ -53,7 +53,7 @@ climate_mod.influences = {}
|
||||
climate_mod.current_weather = {}
|
||||
climate_mod.current_effects = {}
|
||||
climate_mod.forced_weather = {}
|
||||
climate_mod.forced_wind = nil
|
||||
climate_mod.forced_enviroment = {}
|
||||
|
||||
-- handle persistent mod storage
|
||||
climate_mod.state = dofile(modpath .. "/lib/datastorage.lua")
|
||||
|
@ -55,6 +55,22 @@ minetest.register_chatcommand("weather", {
|
||||
})
|
||||
|
||||
-- set base heat to increase or decrease global climate temperatures
|
||||
minetest.register_chatcommand("set_base_heat", {
|
||||
params = "<heat>",
|
||||
description = "Override the weather algorithm's base heat",
|
||||
privs = { weather = true },
|
||||
func = function(playername, param)
|
||||
if param == nil or param == "" then
|
||||
minetest.chat_send_player(playername, "Provide a number to modify the base heat")
|
||||
return
|
||||
end
|
||||
if param == "auto" then param = 0 end
|
||||
climate_mod.settings.heat = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Base heat changed")
|
||||
end
|
||||
})
|
||||
|
||||
-- override global heat levels with given value
|
||||
minetest.register_chatcommand("set_heat", {
|
||||
params = "<heat>",
|
||||
description = "Override the weather algorithm's base heat",
|
||||
@ -64,12 +80,33 @@ minetest.register_chatcommand("set_heat", {
|
||||
minetest.chat_send_player(playername, "Provide a number to modify the base heat")
|
||||
return
|
||||
end
|
||||
climate_mod.settings.heat = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Heat changed")
|
||||
if param == "auto" then
|
||||
climate_mod.forced_enviroment.heat = nil
|
||||
minetest.chat_send_player(playername, "Heat value reset")
|
||||
else
|
||||
climate_mod.forced_enviroment.heat = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Heat value changed")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- set base heat to increase or decrease global climate humidity
|
||||
minetest.register_chatcommand("set_base_humidity", {
|
||||
params = "<humidity>",
|
||||
description = "Override the weather algorithm's base humidity",
|
||||
privs = { weather = true },
|
||||
func = function(playername, param)
|
||||
if param == nil or param == "" then
|
||||
minetest.chat_send_player(playername, "Provide a number to modify the base humidity")
|
||||
return
|
||||
end
|
||||
if param == "auto" then param = 0 end
|
||||
climate_mod.settings.humidity = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Base humidity changed")
|
||||
end
|
||||
})
|
||||
|
||||
-- override global humidity with given value
|
||||
minetest.register_chatcommand("set_humidity", {
|
||||
params = "<humidity>",
|
||||
description = "Override the weather algorithm's base humidity",
|
||||
@ -79,8 +116,13 @@ minetest.register_chatcommand("set_humidity", {
|
||||
minetest.chat_send_player(playername, "Provide a number to modify the base humidity")
|
||||
return
|
||||
end
|
||||
climate_mod.settings.humidity = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Humidity changed")
|
||||
if param == "auto" then
|
||||
climate_mod.forced_enviroment.humidity = nil
|
||||
minetest.chat_send_player(playername, "Humidity value reset")
|
||||
else
|
||||
climate_mod.forced_enviroment.humidity = tonumber(param)
|
||||
minetest.chat_send_player(playername, "Humidity value changed")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
@ -99,9 +141,11 @@ minetest.register_chatcommand("set_wind", {
|
||||
local wind_x = arguments[1]
|
||||
local wind_z = arguments[2]
|
||||
if wind_x == "auto" then
|
||||
climate_mod.forced_wind = nil
|
||||
climate_mod.forced_enviroment.wind = nil
|
||||
elseif wind_x == nil or wind_z == nil then
|
||||
minetest.chat_send_player(playername, "Invalid wind configuration")
|
||||
else
|
||||
climate_mod.forced_wind = vector.new({
|
||||
climate_mod.forced_enviroment.wind = vector.new({
|
||||
x = tonumber(wind_x),
|
||||
y = 0,
|
||||
z = tonumber(wind_z)
|
||||
@ -131,11 +175,14 @@ minetest.register_chatcommand("set_weather", {
|
||||
local arguments = {}
|
||||
for w in param:gmatch("%S+") do table.insert(arguments, w) end
|
||||
local weather = arguments[1]
|
||||
if climate_mod.weathers[weather] == nil then
|
||||
if weather == nil or climate_mod.weathers[weather] == nil then
|
||||
minetest.chat_send_player(playername, "Unknown weather preset")
|
||||
return
|
||||
end
|
||||
local status
|
||||
if arguments[2] == nil or arguments[2] == "" then
|
||||
arguments[2] = "on"
|
||||
end
|
||||
if arguments[2] == "on" then
|
||||
status = true
|
||||
elseif arguments[2] == "off" then
|
||||
|
@ -1,24 +1,21 @@
|
||||
local environment = {}
|
||||
|
||||
local function get_heat_time()
|
||||
local time = minetest.get_timeofday()
|
||||
return climate_api.utility.normalized_cycle(time) * 0.6 + 0.7
|
||||
end
|
||||
|
||||
local function get_heat_height(y)
|
||||
return climate_api.utility.rangelim((-y + 10) / 15, -10, 10)
|
||||
end
|
||||
|
||||
function environment.get_heat(pos)
|
||||
if climate_mod.forced_enviroment.heat ~= nil then
|
||||
return climate_mod.forced_enviroment.heat
|
||||
end
|
||||
local base = climate_mod.settings.heat
|
||||
local biome = minetest.get_heat(pos)
|
||||
local height = get_heat_height(pos.y)
|
||||
local time = get_heat_time()
|
||||
local height = climate_api.utility.rangelim((-pos.y + 10) / 15, -10, 10)
|
||||
local time = climate_api.utility.normalized_cycle(minetest.get_timeofday()) * 0.6 + 0.7
|
||||
local random = climate_mod.state:get_float("heat_random");
|
||||
return (base + biome + height) * time * random
|
||||
end
|
||||
|
||||
function environment.get_humidity(pos)
|
||||
if climate_mod.forced_enviroment.humidity ~= nil then
|
||||
return climate_mod.forced_enviroment.humidity
|
||||
end
|
||||
local base = climate_mod.settings.humidity
|
||||
local biome = minetest.get_humidity(pos)
|
||||
local random = climate_mod.state:get_float("humidity_random");
|
||||
@ -26,13 +23,15 @@ function environment.get_humidity(pos)
|
||||
return (base + biome * 0.7 + random_base * 0.3) * random
|
||||
end
|
||||
|
||||
function environment.get_wind()
|
||||
if climate_mod.forced_wind ~= nil then
|
||||
return climate_mod.forced_wind
|
||||
function environment.get_wind(pos)
|
||||
if climate_mod.forced_enviroment.wind ~= nil then
|
||||
return climate_mod.forced_enviroment.wind
|
||||
end
|
||||
local wind_x = climate_mod.state:get_float("wind_x")
|
||||
local wind_z = climate_mod.state:get_float("wind_z")
|
||||
return vector.new({ x = wind_x, y = 0, z = wind_z })
|
||||
local base_wind = vector.new({ x = wind_x, y = 0, z = wind_z })
|
||||
local height_modifier = climate_api.utility.sigmoid(pos.y, 2, 0.02, 1)
|
||||
return vector.multiply(base_wind, height_modifier)
|
||||
end
|
||||
|
||||
function environment.get_weather_presets(player)
|
||||
|
@ -33,13 +33,13 @@ climate_api.register_influence("biome", function(pos)
|
||||
return biome
|
||||
end)
|
||||
|
||||
climate_api.register_global_influence("windspeed", function()
|
||||
local wind = climate_api.environment.get_wind()
|
||||
climate_api.register_influence("windspeed", function(pos)
|
||||
local wind = climate_api.environment.get_wind(pos)
|
||||
return vector.length(wind)
|
||||
end)
|
||||
|
||||
climate_api.register_global_influence("wind_yaw", function()
|
||||
local wind = climate_api.environment.get_wind()
|
||||
local wind = climate_api.environment.get_wind({x = 0, y = 0, z = 0})
|
||||
if vector.length(wind) == 0 then return 0 end
|
||||
return minetest.dir_to_yaw(wind)
|
||||
end)
|
||||
|
@ -49,7 +49,6 @@ elseif mod_pova then
|
||||
|
||||
-- fallback to vanilla override as last resort
|
||||
else
|
||||
local physics = {}
|
||||
local function apply_physics(player)
|
||||
local playername = player:get_player_name()
|
||||
local override = { speed = 1, jump = 1, gravity = 1 }
|
||||
|
@ -37,7 +37,7 @@ function trigger.test_condition(condition, env, goal)
|
||||
return false
|
||||
else
|
||||
value = env[condition]
|
||||
return type(value) ~= "nil" and goal == value
|
||||
return type(value) == "nil" or goal == value
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
# Lower values will significantly increase overall performance at the cost of rougher looking effects.
|
||||
climate_api_tick_speed (Update speed of weather effects) float 1 0.1 10
|
||||
|
||||
# This value regulated how many particles will be spawned.
|
||||
# This value regulates how many particles will be spawned.
|
||||
# A value of 1 will use the recommended amount of particles.
|
||||
# Lower values can possible increase performance.
|
||||
climate_api_particle_count (Multiplicator for used particles) float 1 0.1 2
|
||||
|
Loading…
Reference in New Issue
Block a user