master
root 2021-02-06 15:42:53 +01:00
parent 96efd8649a
commit 0deba124e7
226 changed files with 1044 additions and 4446 deletions

View File

@ -1,18 +0,0 @@
[submodule "climate_api"]
path = climate_api
url = https://github.com/t-affeldt/climate_api.git
[submodule "regional_weather"]
path = regional_weather
url = https://github.com/t-affeldt/regional_weather.git
[submodule "moon_phases"]
path = moon_phases
url = https://github.com/t-affeldt/minetest_moon_phase
[submodule "lightning"]
path = lightning
url = https://github.com/minetest-mods/lightning.git
[submodule "sailing_kit"]
path = sailing_kit
url = https://github.com/t-affeldt/sailing_kit.git
[submodule "mobkit"]
path = mobkit
url = https://github.com/TheTermos/mobkit

View File

@ -1,73 +0,0 @@
# Climate Modpack
Not every biome is the same and neither should their weather be.
The complete weather bundle for any Minetest game.
![](https://raw.githubusercontent.com/t-affeldt/regional_weather/master/screenshot.webp)
Source & Information on [Github](https://github.com/t-affeldt/climate) and the [Forum](https://forum.minetest.net/viewtopic.php?t=24569).
## Included Mods
- Climate API: The heart and core of this pack. This mod provides a vast weather and effect engine
- Regional Weather: What you will see on the screen. A bundle of weather presets and environment effects with beautiful visuals
- Moon Phases: Makes your sky dynamic by cycling through eight different phases
- Lightning by Auke Kok (sofar): Adds random lightning strikes during rainstorms
## Recommended Mods
- [Sailing Kit](https://github.com/t-affeldt/sailing_kit): A fork of [Termos' sailboat](https://forum.minetest.net/viewtopic.php?t=23520) to support the new wind system.
## Cloning Instructions
This modpack uses submodules to always be up-to-date.
Downloading the repository as a ZIP file leaves the mod folders empty, so you will have to download them manually. If you are using git commands then make sure you set the *recursive* flag instead: ``git clone https://github.com/t-affeldt/climate.git --recursive``. If you forget to set this flag, then the mod folders will be empty. You will also need to run ``git pull`` from within every mod folder in order to update the modpack.
Check out the [Git SCM guide on submodules](https://git-scm.com/book/de/v2/Git-Tools-Submodule) for more information.
## Troubleshooting
Generally speaking, most mods should be compatible.
If you notice __odd movement speeds__ or jump heights of players, you should check for mods that also modify player physics. Use a compatibility mod like [player_monoids](https://github.com/minetest-mods/player_monoids) or [playerphysics](https://forum.minetest.net/viewtopic.php?t=22172) to get rid of this problem. This requires the conflicting mod to also support the chosen compatibility layer.
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 in the climate_api mod configuration 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.
If you experience __performance issues__, the *Performance* section of Climate API's configuration section is a great place to start looking for a solution.
## Chat Commands
### Climate API
- ``/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). 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 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.
### Moon Phases
This mod comes with two commands to print or change the current moon phase.
- Use ``/moonphase`` to view the currently active phase.
- Use ``/set_moonphase <phase>`` to change it. ``<phase>`` has to be a full number between 1 and 8.
- Use ``/set_moonstyle <style>`` to choose a texture preset. ``classic`` will result in a quadratic moon
inspired by default Minetest. ``realistic`` will result in 256x images of the real moon.
In order to change the phase, you will need the corresponding privilege.
Use ``/grant <player> moonphase`` to grant it.
## Configuration Options
The individual mods offer a lot of customization options. Make sure to check the respective README files for more information.
## 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
All parts of this modpack are using free software licenses.
Check the individual README and LICENSE files of each mod for information.
### Assets in screenshots
- Screenshots and editing: *CC BY-SA (3.0)* by me
- Logos and artwork: *CC BY-SA (3.0)* by Cap
- Lato Font (for the Logo): *OFL* by Łukasz Dziedzic from http://www.latofonts.com/lato-free-fonts/
- Source Sans Pro (for the subtitles): *OFL*, see https://fonts.google.com/specimen/Source+Sans+Pro
- Used texture pack: Polygonia (128px edition) *CC BY-SA (4.0)* by Lokrates. See https://forum.minetest.net/viewtopic.php?f=4&t=19043

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at t.affeldt@tu-braunschweig.de. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,157 +0,0 @@
### GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the
terms and conditions of version 3 of the GNU General Public License,
supplemented by the additional permissions listed below.
#### 0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the
GNU General Public License.
"The Library" refers to a covered work governed by this License, other
than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
#### 1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
#### 2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
- a) under this License, provided that you make a good faith effort
to ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
- b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
#### 3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a
header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
- a) Give prominent notice with each copy of the object code that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the object code with a copy of the GNU GPL and this
license document.
#### 4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken
together, effectively do not restrict modification of the portions of
the Library contained in the Combined Work and reverse engineering for
debugging such modifications, if you also do each of the following:
- a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the Combined Work with a copy of the GNU GPL and this
license document.
- c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
- d) Do one of the following:
- 0) Convey the Minimal Corresponding Source under the terms of
this License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- 1) Use a suitable shared library mechanism for linking with
the Library. A suitable mechanism is one that (a) uses at run
time a copy of the Library already present on the user's
computer system, and (b) will operate properly with a modified
version of the Library that is interface-compatible with the
Linked Version.
- e) Provide Installation Information, but only if you would
otherwise be required to provide such information under section 6
of the GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the Application
with a modified version of the Linked Version. (If you use option
4d0, the Installation Information must accompany the Minimal
Corresponding Source and Corresponding Application Code. If you
use option 4d1, you must provide the Installation Information in
the manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.)
#### 5. Combined Libraries.
You may place library facilities that are a work based on the Library
side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
- a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities, conveyed under the terms of this License.
- b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
#### 6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
as you received it specifies that a certain numbered version of the
GNU Lesser General Public License "or any later version" applies to
it, you have the option of following the terms and conditions either
of that published version or of any later version published by the
Free Software Foundation. If the Library as you received it does not
specify a version number of the GNU Lesser General Public License, you
may choose any version of the GNU Lesser General Public License ever
published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -1,117 +0,0 @@
# Climate API
A powerful engine for weather presets and visual effects.
Requires a weather pack like [Regional Weather](https://github.com/t-affeldt/regional_weather).
![](https://raw.githubusercontent.com/t-affeldt/climate_api/master/screenshot.png)
Use the regional climate to set up different effects for different regions.
Control where your effects are activated based on temperature, humidity, wind,
position, light level or a completely custom activator.
Climate API provides temperature and humidity values on a block-per-block basis
that follow the seasons, day / night cycle and random changes.
Make it rain, change the sky or poison the player - it's up to you.
## Troubleshooting
Generally speaking, most mods should be compatible.
If you notice __odd movement speeds__ or jump heights of players, you should check for mods that also modify player physics. Use a compatibility mod like [player_monoids](https://github.com/minetest-mods/player_monoids) or [playerphysics](https://forum.minetest.net/viewtopic.php?t=22172) to get rid of this problem. This requires the conflicting mod to also support the chosen compatibility layer.
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.
__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
- [Moon Phases](https://github.com/t-affeldt/minetest_moon_phase): Complements weather effects with dynamic sky changes and a full moon cycle
- [Sailing Kit](https://github.com/t-affeldt/sailing_kit) (Fork): Uses Climate API's new wind system to sail across the sea.
The following mods complement Climate API particularly well:
- [Lightning](https://github.com/minetest-mods/lightning): Adds to heavy rain by enabling additional lightning effects
- [Ambience](https://notabug.org/TenPlus1/ambience): Plays some nice ambient sound effects based on where you are.
## Chat Commands
- ``/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). 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 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.
## Configuration Options
You can find all mod configuration options in your Minetest launcher.
Go to ``Settings → All Settings → Mods → climate_api`` to change them.
Individual weather packs may provide additional configuration options in their respective mod configuration section.
### Performance
- ``Update speed of weather effects`` (default 1.0):
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 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):
If set to true, weather packs are allowed to register node update handlers.
These can be used to dynamically place snow layers, melt ice, or hydrate soil.
- ``Include wind speed in damage checks`` (default true):
If set to true, Climate API will factor in wind speed and obstacles to determine damage sources.
If set to false, a simple check will be used whether the player is outside.
### Weather Effects
- ``Cause player damage`` (default true):
If set to true, dangerous weather presets will damage affected players over time.
- ``Show particle effects`` (default true):
If set to true, weather effects (like rain) are allowed to render particles.
Deactivating this feature will prevent some presets from being visible.
For performance considerations it is recommended to decrease the amount of particles instead.
- ``Override the skybox`` (default true):
If set to true, weather effects are allowed to modify a player's sky.
This includes skybox, sun, moon, and clouds (also used for fog effects).
Running this mod on Minetest 5.1.2 or earlier versions will automatically disable this feature.
- ``Display HUD overlays`` (default true):
If set to true, weather effects are allowed to render an image on top of the gameplay.
This is usually an optional effect used to increase immersion (like a frozen-over camera in a snow storm).
### Environment
- ``Global base temperature`` (default 0):
This value will be added to all biome's base temperatures before applying random modifiers.
Every unit here will increase the global base heat by one degree Fahrenheit.
Negative values will cool down global base heat respectively.
- ``Global base humidity`` (default 0):
This value will be added to all biome's base humidity before applying random modifiers.
Every unit here will increase the global base humidity by one percent.
Negative values will dry up global base humidity respectively.
- ``Time rate of weather changes`` (default 1.0):
This value regulates how quickly environment factors like heat, humidity and wind are changing.
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 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.
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
## Assets in screenshots
- Screenshots and editing by me: *CC BY-SA (3.0)*
- Logos and artwork: *CC BY-SA (3.0)* by Cap
- Lato Font (for the Logo): *OFL* by Łukasz Dziedzic from http://www.latofonts.com/lato-free-fonts/
- Source Sans Pro (for the subtitles): *OFL*, see https://fonts.google.com/specimen/Source+Sans+Pro
- Used texture pack: Polygonia (128px edition) *CC BY-SA (4.0)* by Lokrates. See https://forum.minetest.net/viewtopic.php?f=4&t=19043

View File

@ -1,36 +0,0 @@
# TODO
## 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
## Future Plans & Ideas
- Complete season system
- crops grow better in their respective season or worse in winter
- regrowing apples, lemons, etc. in their respective months
- holidays and reminders via chat commands
- day/night cycle adjusted to season
- special events like a bloodmoon -> increased mob spawns
- water can freeze over in winter
- Fantasy weather effects
- pretty skyboxes
- swirling flower petals, mushroom spores, etc. in fitting biomes
- underground environment effects
- space effects at high y-level (meteors, magnetic storms, different skybox)
- Eco Pack (with climate change)
- Integration with Technic mods, etc.
- Track planted trees vs chopped wood, killed mobs, etc.
- Ecological footprint influences weather
- Extreme weather scenarios and desasters
- Tornados, poisonous rain that kills crops and animals, bush fires,...
- Survival Pack
- Body temperature becomes survival aspect
- Use local heat as base value
- swimming will cool down
- standing near fire will warm up
- craftable warm clothes
- metal armor will worsen heat issues
- A flag indicating wind direction

View File

@ -1,189 +0,0 @@
# 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. So far, all parameters are mandatory.
## Custom Weather Registration
### Register Weather Preset
``climate_api.register_weather(name, conditions, effects)``
Invoke this function in order to create and register a new weather preset. Presets control which effects are to be applied to a player under specific circumstances. As an example, a preset for rain could require a high level of humidity and apply particle and sound effects.
__Parameters__:
- ``name <string>``: A unique identifier resembling the new weather preset.
Should be prefixed with the mod's name in a way that could look like ``mymod:awesome_weather``. This name should only be used once.
- ``conditions <table>``: An associative array that checks weather influences for specified values. Keys should be the name of an influence, values should be of matching type for repective influence. Keys can be prefixed with ``min_`` to accept any value equal or higher than influence value. A prefix of ``max_`` will accept any value lesser than influence value. A prefix of ``has_`` can be used in conjunction with a numeric array as a value. It will accept any influence value that is present in the specified table. Omitting a prefix will accept the specified value only. All table entries have to be matched positively for the weather preset to be applied.
- ``conditions <function>``: For more control, a function can be specified instead of a conditions table. The function will receive a table as its first parameter, consisting of key-value pairs indicating the current value for each weather influence. The function is expected to return true if the weather preset is to be applied or false otherwise.
- ``effects <table>``: An associative array indicating which weather effects are to be applied whenever the weather preset is active. The key should be a registered weather effect name. The value will be passed as a parameter to the effect. Look at the documentation of individual effects to determine valid values.
- ``effects <function>``: A generator function that returns a set of weather effects and its parameters. This function will receive a table as its first parameter, consisting of key-value pairs indicating the current value for each weather influence. It is expected to return a table in the same fashion as ``effects <table>`` would have looked like.
__Returns__: ``nil``
### Register Weather Effect
``climate_api.register_effect(name, handler, htype)``
__Parameters__:
- ``name <string>``: A unique identifier resembling the new weather effect.
Should be prefixed with the mod's name in a way that could look like ``mymod:special_effect``. Call this function multiple times with the same name in order to apply multiple handler methods to the same effect.
- ``handler <function>``: This function will be called whenever players are affected by the registered effect. It receives a single parameter containing an accociative array. The keys represent player names and the values represent the set of applied preset parameters. This set is an accociative array as well with the keys representing the names of applied weather presets and the values representing the supplied data from those presets. This parameter could look like this:
``{ singleplayer = {"mymod:awesome_weather" = "a", "mymod:amazing_weather" = "b"} }``. If ``htype`` is ``tick`` then the list of players represents all currently affected players. If it is ``start`` or ``end`` then the list contains all players going though that change.
- ``htype <"start" | "tick" | "end">``: Determines when the handler will be called. ``start`` results in a callback whenever an effect is applied to at least one player, meaning that the very first weather preset applies it. ``tick`` results in a callback every update cycle as long as at least one player has the effect from at least one preset. ``end`` results in a callback whenever at least one player loses the effect completely.
__Returns__: ``nil``
### Set Update Cycle for Effect
``climate_api.set_effect_cycle(name, cycle)``
__Parameters__:
- ``name <string>``: The identifier of a registered weather effect
- ``cycle <number>``: The minimal time between update calls to registered effect handlers in seconds. This value defaults to ``climate_api.DEFAULT_CYCLE`` (2.0s). Other values are ``climate_api.SHORT_CYCLE`` (0s) for frequent update calls (like for particle effects) and ``climate_api.LONG_CYCLE`` (5.0s) for ressource intensive tasks and timed effects (like lightning strikes). You can also use any other custom number representing the amount of time in seconds.
__Returns__: ``nil``
### Register Global Environment Influence
``climate_api.register_global_influence(name, func)``
__Parameters__:
- ``name <string>`` A unique name identifying the registered influence
- ``func <function>``: A generator function that returns some value which is in turn supplied to weather presets and can be used as a condition.
__Returns__: ``nil``
### Register Local Environment Influence
``climate_api.register_influence(name, func)``
__Parameters__:
- ``name <string>`` A unique name identifying the registered influence
- ``func <function>``: A generator function that returns some value which is in turn supplied to weather presets and can be used as a condition. This function will receive a vector as its single parameter indicating the current position.
__Returns__: ``nil``
### Register Active Block Modifier
``climate_api.register_abm(config)``
## Environment Access
### Get Temperature At Position
``climate_api.environment.get_heat(pos)``
__Parameter__: ``pos <vector>``: Coordinates of requested location
__Returns__: ``<number>`` indicating current temperature in °F
### Get Humidity At Position
``climate_api.environment.get_humidity(pos)``
__Parameter__: ``pos <vector>``: Coordinates of requested location
__Returns__: ``<number>`` indicating current humidity
### Get Current Windspeed
``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
### Get Active Weather Presets
``climate_api.environment.get_weather_presets(player)``
### Get Active Weather Effects
``climate_api.environment.get_effects(player)``
## Skybox Modification
### Add Sky Configuration Layer
``climate_api.skybox.add(playername, name, sky)``
### Remove Sky Configuration Layer
``climate_api.skybox.remove(playername, name)``
### Update Player Sky
``climate_api.skybox.update(playername)``
## Player Physics Modifications
Climate API provides an easy way of modfying player physics in a compatible way.
The API is similar to those of ``player_monoids`` or ``playerphysics`` because it also uses multiplication to account for multiple modifiers.
In fact, these functions use ``player_monoids`` under the hud if that mod is available. If not, they will fall back to ``playerphysics``, ``pova``, or native overrides in that order.
### Add Physics Modifier
``climate_api.player_physics.add(id, player, effect, value)``
Register a new modifier that will be multiplied with the current value to set the new physics factor. Call this function again with the same id in order to change an existing modifier.
__Parameters__:
- ``id <string>``: A unique name used to identify the modifier. Should be prefixed with the mod's name.
- ``player <ObjectRef>``: The player affected by the physics change
- ``effect <"speed" | "jump" | "gravity">``: The type of physics to be changed
- ``value <number>``: The multiplicator. Use values between 0 and 1 to reduce physics attribute. Use values above 1 to increase it.
__Returns__: ``nil``
### Remove Physics Modifier
``climate_api.player_physics.remove(id, player, effect)``
Use this function to completely remove a physics modifer from the attribute calculation.
__Parameters__:
- ``id <string>``: The name used in ``player_physics.add`` that identifies a registered modifier
- ``player <ObjectRef>``: The player affected by the physics change
- ``effect <"speed" | "jump" | "gravity">``: The type of physics to be changed
__Returns__: ``nil``
## Utility Functions
### Merge Tables
``climate_api.utility.merge_tables(a, b)``
This function will merge two given accociative tables and return the result.
If in conflict, attributes of table B will override those of table A.
This is especially useful when assigning default values to a specified configuration with possibly missing entries.
Note that this function will also modify table A. If you want to prevent that, you should copy the table first: ``climate_api.utility.merge_tables(table.copy(a), b)``.
__Parameters__:
- ``a <table>``: The base table consisting of default values or other data
- ``b <table>``: The prioritized table to merge with, and possibly override A
__Returns__: ``<table>`` consisting of all attributes from A and B.
### Limit Numeric Boundaries
``climate_api.utility.rangelim(value, min, max)``
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``.

View File

@ -1,83 +0,0 @@
--[[
# Player Damage Effect
Use this effect to damage a player during dangerous weather events.
Expects a table as the parameter containing the following values:
- value <int> [1]: The amount of damage to be applied per successful roll.
- rarity <int> [1]: Defines a 1/x chance per cycle for the player to get damaged. Higher values result in less frequent damage.
- check <table> [nil]: Use an additional outdoors check before applying damage. Consists of the following values:
- type <"light"|"raycast"> ["light"] (Whether the light level should be used a raycast should be performed)
- height <number> [0] (Height offset of weather origin from the player. Only used for raycasts)
- velocity <number> [1] (Velocity of damaging particles. Only used for raycasts)
- use_wind <bool> [true] (Whether the wind should be factored in. Only used for raycasts)
]]
if not minetest.is_yes(minetest.settings:get_bool("enable_damage"))
or not climate_mod.settings.damage then return end
local EFFECT_NAME = "climate_api:damage"
local rng = PcgRandom(7819792)
local function check_hit(player, ray)
local ppos = vector.add(player:get_pos(), {x=0, y=1, z=0})
if ray.type ~= nil and ray.type ~= "light" and ray.type ~= "raycast" then
minetest.log("warning", "[Climate API] Invalid damage check configuration")
return false
end
-- use light level if specified or in performance mode
if ray.type == nil
or ray.type == "light"
or not climate_mod.settings.raycast then
return minetest.get_node_light(ppos, 0.5) == 15
end
-- 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(origin)
local velocity = ray.velocity or 1
local windpos = vector.multiply(
vector.normalize(vector.add({ x = 0, y = -velocity, z = 0 }, wind)),
-vector.length(wind)
)
origin = vector.add(origin, windpos)
end
local ray = minetest.raycast(origin, ppos)
local obj = ray:next()
-- found nothing
if obj == nil then return false end
-- found node
if obj.type ~= "object" then return false end
-- found different entity
if not obj.ref:is_player() then return false end
-- found another player
if obj.ref:get_player_name() ~= player:get_player_name() then return false end
return true
end
local function calc_damage(player, dmg)
if dmg.value == nil then dmg.value = 1 end
if dmg.rarity == nil then dmg.rarity = 1 end
-- check if damage should be applied
if rng:next(1, dmg.rarity) ~= 1 then return 0 end
if dmg.check ~= nil then
-- check for obstacles in the way
if not check_hit(player, dmg.check) then return 0 end
end
return dmg.value
end
local function handle_effect(player_data)
for playername, data in pairs(player_data) do
local player = minetest.get_player_by_name(playername)
local hp = player:get_hp()
for weather, dmg in pairs(data) do
hp = hp - calc_damage(player, dmg)
end
-- deal damage to player
player:set_hp(hp, "weather damage")
end
end
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")

View File

@ -1,103 +0,0 @@
--[[
# HUD Overlay Effect
Use this effect to display a fullscreen image as part of a player's HUD.
Expects a table as the parameter containing the following values:
- ``file <string>``: The name (including file ending) if the image to be displayed
- ``z_index <number>`` (optional): The z_index to forward to player.hud_add. Defaults to 1
- ``color_correction <bool>`` (optional): Whether the image should automatically darken based on current light. Defaults to false.
]]
if not climate_mod.settings.hud_overlay then return end
local EFFECT_NAME = "climate_api:hud_overlay"
local handles = {}
local function apply_hud(pname, weather, hud)
local player = minetest.get_player_by_name(pname)
if player == nil then return end
if handles[pname] == nil then handles[pname] = {} end
if handles[pname][weather] ~= nil then
player:hud_remove(handles[pname][weather])
end
local file
if hud.color_correction then
local pos = vector.add(player:get_pos(), {x = 0, y = 1, z = 0})
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
local light_file = hud.file .. "^[opacity:" .. light
file = "(" .. light_file .. ")^(" .. dark_file .. ")"
else
file = hud.file
end
local handle = player:hud_add({
name = weather,
hud_elem_type = "image",
position = {x = 0, y = 0},
alignment = {x = 1, y = 1},
scale = { x = -100, y = -100},
z_index = hud.z_index,
text = file,
offset = {x = 0, y = 0}
})
handles[pname][weather] = handle
end
local function remove_hud(pname, weather, hud)
local player = minetest.get_player_by_name(pname)
if player == nil then return end
if handles[pname] == nil or handles[pname][weather] == nil then return end
local handle = handles[pname][weather]
player:hud_remove(handle)
handles[pname][weather] = nil
end
local function start_effect(player_data)
for playername, data in pairs(player_data) do
for weather, value in pairs(data) do
apply_hud(playername, weather, value)
end
end
end
local function handle_effect(player_data, prev_data)
for playername, data in pairs(player_data) do
for weather, value in pairs(data) do
if prev_data[playername][weather] == nil
or value.color_correction == true
or prev_data[playername][weather].color_correction == true
or value.file ~= prev_data[playername][weather].file
or value.z_index ~= prev_data[playername][weather].z_index
then
apply_hud(playername, weather, value)
end
end
end
for playername, data in pairs(prev_data) do
for weather, value in pairs(data) do
if player_data[playername][weather] == nil then
remove_hud(playername, weather, value)
end
end
end
end
local function stop_effect(prev_data)
for playername, data in pairs(prev_data) do
for weather, value in pairs(data) do
remove_hud(playername, weather, value)
end
end
end
climate_api.register_effect(EFFECT_NAME, start_effect, "start")
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")
climate_api.register_effect(EFFECT_NAME, stop_effect, "stop")

View File

@ -1,215 +0,0 @@
--[[
# Particle Effect
Use this effect to render downfall or similar visuals using particles.
Expects a table as the parameter containing information for the spawner.
All values for ParticleSpawner definitions are valid.
See https://minetest.gitlab.io/minetest/definition-tables/#particlespawner-definition
Furthermore, the following default values have been changed:
- time <int> [0.5] (reduced time results in smoother position updates, but more lag)
- collisiondetection <bool> [true]
- collision_removal <bool> [true]
- playername <string> [current player] (Set to empty string to show for everyone)
- vertical <bool> [nil] (Unless explicitly set, particle facing rotation will be automatically set based on direction of velocity)
The following optional values have been introduced for convenience:
- boxsize <vector> [nil] (Overrides minpos and maxpos based on specified sizes per direction with the player in the center)
- boxsize <number> [nil] (If set to a number, the resulting vector will have the specified size in all directions)
- v_offset <int> [0] (Use in conjunctin with boxsize. Adds specified height to minpos and maxpos y-coordinates)
- attach_to_player <bool> [false] (Overrides attached object with current player)
The following optional values have been expanded with additional value types for convenience:
- size <int> [nil] (Overrides both minsize and maxsize if set)
- minvel <int> [nil] (Overrides minvel with a downward facing vector of specified length)
- maxvel <int> [nil] (Overrides maxvel with a downward facing vector of specified length)
- velocity <vector | int> [nil] (Overrides both minvel and maxvel if set)
- minacc <int> [nil] (Overrides minacc with a downward facing vector of specified length)
- maxacc <int> [nil] (Overrides maxacc with a downward facing vector of specified length)
- acceleration <vector | int> [nil] (Overrides both minacc and maxacc if set)
The following new behaviours have been introduced:
- use_wind <bool> [true] (Adjusts velocity and position for current windspeed)
- detach <bool> [false] (Unless enabled, considers positions as relative to current player as if spawner's position would be attached)
- adjust_for_velocity <bool> [true] (Corrects position of particle spawner by player's movement speed. Only applicable if detach = false and not manually attached)
]]
if not climate_mod.settings.particles then return end
local EFFECT_NAME = "climate_api:particles"
local CYCLE_LENGTH = climate_api.SHORT_CYCLE
-- parse config by injecting default values and adding additional parameters
local function parse_config(player, particles)
-- override default values with more useful ones
local defaults = {
time = 0.5,
collisiondetection = true,
collision_removal = true,
playername = player:get_player_name(),
use_wind = true,
attach_to_player = false,
detach = false,
adjust_for_velocity = true
}
-- inject missing default values into specified config
local config = climate_api.utility.merge_tables(defaults, particles)
-- scale particle amount based on mod config
if particles.amount ~= nil then
config.amount = particles.amount * climate_mod.settings.particle_count
end
-- restore default visibility if specified
if particles.playername == "" then
config.playername = nil
end
-- provide easier param for exptime
if particles.expirationtime ~= nil then
config.minexptime = particles.expirationtime
config.maxexptime = particles.expirationtime
config.expirationtime = nil
end
-- provide easier param for size
if particles.size ~= nil then
config.minsize = particles.size
config.maxsize = particles.size
config.size = nil
end
-- randomly select a texture when given a table
if type(particles.texture) == "table" then
config.texture = particles.texture[math.random(#particles.texture)]
end
if particles.pos ~= nil then
config.minpos = particles.pos
config.maxpos = particles.pos
config.pos = nil
end
-- provide easier size based param for position
if type(particles.boxsize) == "number" then
particles.boxsize = {
x = particles.boxsize,
y = particles.boxsize,
z = particles.boxsize
}
end
if particles.boxsize ~= nil then
local size_x = particles.boxsize.x or 0
local size_y = particles.boxsize.y or 0
local size_z = particles.boxsize.z or 0
local v_offset = particles.v_offset or 0
v_offset = v_offset + (size_y / 2)
config.minpos = {
x = -size_x / 2,
y = v_offset - (size_y / 2),
z = -size_z / 2
}
config.maxpos = {
x = size_x / 2,
y = v_offset + (size_y / 2),
z = size_z / 2
}
config.size_x = nil
config.size_y = nil
config.size_z = nil
config.v_offset = nil
end
-- provide easy param to define unanimous falling speed
if particles.velocity ~= nil then
particles.minvel = particles.velocity
particles.maxvel = particles.velocity
config.velocity = nil
end
if type(particles.minvel) == "number" then
config.minvel = { x = 0, y = -particles.minvel, z = 0 }
end
if type(particles.maxvel) ~= nil then
config.maxvel = { x = 0, y = -particles.maxvel, z = 0 }
end
-- provide easy param to define unanimous falling acceleration
if particles.acceleration ~= nil then
particles.minacc = particles.acceleration
particles.maxacc = particles.acceleration
config.acceleration = nil
end
if type(particles.minacc) == "number" then
config.minacc = { x = 0, y = -particles.minacc, z = 0 }
end
if type(particles.maxacc) == "number" then
config.maxacc = { x = 0, y = -particles.maxacc, z = 0 }
end
-- attach particles to current player if specified
if config.attach_to_player then
config.attached = player
end
config.attach_to_player = nil
-- attach coordinates to player unless specified or already attached
if (not config.detach) and config.attached == nil then
local ppos = player:get_pos()
config.minpos = vector.add(config.minpos, ppos)
config.maxpos = vector.add(config.maxpos, ppos)
-- correct spawn coordinates to adjust for player movement
if config.adjust_for_velocity then
local velocity = player:get_player_velocity()
config.minpos = vector.add(config.minpos, velocity)
config.maxpos = vector.add(config.maxpos, velocity)
end
end
config.detach = nil
config.adjust_for_velocity = nil
-- move particles in wind direction
if config.use_wind then
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)
-- adjust spawn position for better visibility
local vel = vector.multiply(vector.add(config.minvel, config.maxvel), 0.5)
local windpos = vector.multiply(
vector.normalize(vel),
-vector.length(wind)
)
config.minpos = vector.add(config.minpos, windpos)
config.maxpos = vector.add(config.maxpos, windpos)
end
config.use_wind = nil
-- if unspecified, use 2D or 3D rotation based on movement direction
if particles.vertical == nil then
local vel = vector.multiply(vector.add(config.minvel, config.maxvel), 0.5)
config.vertical = math.abs(vector.normalize(vel).y) >= 0.6
end
return config
end
local function handle_effect(player_data)
for playername, data in pairs(player_data) do
local player = minetest.get_player_by_name(playername)
for weather, value in pairs(data) do
local config = parse_config(player, value)
minetest.add_particlespawner(config)
end
end
end
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")
climate_api.set_effect_cycle(EFFECT_NAME, CYCLE_LENGTH)

View File

@ -1,44 +0,0 @@
--[[
# Skybox Effect
Use this effect to modify a player's sky, clouds, sun, moon, or stars
Expects a table as the parameter containing the following values:
- ``sky_data <table>`` (optional): Sky paramaters to be applied using player.set_sky
- ``cloud_data <table>`` (optional): Cloud paramaters to be applied using player.set_clouds
- ``sun_data <table>`` (optional): Sun paramaters to be applied using player.set_sun
- ``moon_data <table>`` (optional): Sky paramaters to be applied using player.set_moon
- ``star_data <table>`` (optional): Sky paramaters to be applied using player.set_stars
- ``priority <number>`` (optional): A skybox with higher priority will override lower rated ones (defaults to 1)
]]
if not climate_mod.settings.skybox then return end
local EFFECT_NAME = "climate_api:skybox"
local function handle_effect(player_data, prev_data)
for playername, data in pairs(prev_data) do
for weather, _ in pairs(data) do
if player_data[playername] == nil or player_data[playername][weather] == nil then
climate_api.skybox.remove(playername, weather)
end
end
end
for playername, data in pairs(player_data) do
for weather, value in pairs(data) do
climate_api.skybox.add(playername, weather, value)
end
climate_api.skybox.update(playername)
end
end
local function remove_effect(player_data)
for playername, data in pairs(player_data) do
for weather, _ in pairs(data) do
climate_api.skybox.remove(playername, weather)
end
climate_api.skybox.update(playername)
end
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.LONG_CYCLE)

View File

@ -1,62 +0,0 @@
--[[
# Sound Loop Effect
Use this effect to loop an ambient sound effect
Expects a table as the parameter containing the following values:
- ``name <string>``: Name of the played sound effect (without .ogg file ending)
- ``gain <number>`` (optional): Volume of the sound (defaults to 1.0)
- ``pitch <number>`` (optional): Pitch of the sound (defaults to 1.0)
]]
if not climate_mod.settings.sound then return end
local EFFECT_NAME = "climate_api:sound"
local FADE_DURATION = climate_api.LONG_CYCLE
local modpath = minetest.get_modpath(minetest.get_current_modname())
local soundloop = dofile(modpath .. "/lib/soundloop.lua")
local function start_sound(pname, sound)
return soundloop.play(pname, sound, FADE_DURATION)
end
local function stop_sound(pname, sound)
return soundloop.stop(pname, sound, FADE_DURATION)
end
local function start_effect(player_data)
for playername, data in pairs(player_data) do
for weather, value in pairs(data) do
start_sound(playername, value)
end
end
end
local function handle_effect(player_data, prev_data)
for playername, data in pairs(player_data) do
for weather, value in pairs(data) do
if prev_data[playername][weather] == nil then
start_sound(playername, value)
end
end
end
for playername, data in pairs(prev_data) do
for weather, value in pairs(data) do
if player_data[playername][weather] == nil then
stop_sound(playername, value)
end
end
end
end
local function stop_effect(prev_data)
for playername, data in pairs(prev_data) do
for weather, value in pairs(data) do
stop_sound(playername, value)
end
end
end
climate_api.register_effect(EFFECT_NAME, start_effect, "start")
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")
climate_api.register_effect(EFFECT_NAME, stop_effect, "stop")

View File

@ -1,85 +0,0 @@
-- warn about outdated Minetest versions
assert(minetest.add_particlespawner, "[Climate API] This mod requires a more current version of Minetest")
-- initialize global API interfaces
climate_api = {}
climate_mod = {}
-- set mod path for file imports
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
-- retrieve boolean value from mod config
local function get_setting_bool(name, default)
local value = minetest.settings:get_bool("climate_api_" .. name)
if type(value) == "nil" then value = default end
return minetest.is_yes(value)
end
-- retrive numeric value from mod config
local function get_setting_number(name, default)
local value = minetest.settings:get("climate_api_" .. name)
if type(value) == "nil" then value = default end
return tonumber(value)
end
-- load settings from config file
climate_mod.settings = {
damage = get_setting_bool("damage", true),
raycast = get_setting_bool("raycast", true),
particles = get_setting_bool("particles", true),
skybox = get_setting_bool("skybox", true),
sound = get_setting_bool("sound", true),
hud_overlay = get_setting_bool("hud_overlay", true),
wind = get_setting_bool("wind", true),
seasons = get_setting_bool("seasons", true),
fahrenheit = get_setting_bool("fahrenheit", false),
block_updates = get_setting_bool("block_updates", true),
heat = get_setting_number("heat_base", 0),
humidity = get_setting_number("humidity_base", 0),
time_spread = get_setting_number("time_spread", 1),
particle_count = get_setting_number("particle_count", 1),
tick_speed = get_setting_number("tick_speed", 1),
volume = get_setting_number("volume", 1),
ceiling_checks = get_setting_number("ceiling_checks", 10),
}
climate_mod.i18n = minetest.get_translator("climate_api")
-- initialize empty registers
climate_mod.weathers = {}
climate_mod.effects = {}
climate_mod.cycles = {}
climate_mod.global_environment = {}
climate_mod.global_influences = {}
climate_mod.influences = {}
climate_mod.current_weather = {}
climate_mod.current_effects = {}
climate_mod.forced_weather = {}
climate_mod.forced_enviroment = {}
-- handle persistent mod storage
climate_mod.state = dofile(modpath .. "/lib/datastorage.lua")
-- import core API
climate_api = dofile(modpath .. "/lib/api.lua")
climate_api.utility = dofile(modpath .. "/lib/api_utility.lua")
climate_api.skybox = dofile(modpath .. "/lib/skybox_merger.lua")
climate_api.player_physics = dofile(modpath .. "/lib/player_physics.lua")
climate_api.environment = dofile(modpath .. "/lib/environment.lua")
climate_mod.world = dofile(modpath .. "/lib/world.lua")
climate_mod.trigger = dofile(modpath .. "/lib/trigger.lua")
-- start event loop and register chat commands
dofile(modpath.."/lib/main.lua")
dofile(modpath.."/lib/commands.lua")
-- register environment influences
dofile(modpath .. "/lib/influences.lua")
-- import predefined environment effects
dofile(modpath .. "/ca_effects/damage.lua")
dofile(modpath .. "/ca_effects/hud_overlay.lua")
dofile(modpath .. "/ca_effects/particles.lua")
dofile(modpath .. "/ca_effects/skybox.lua")
dofile(modpath .. "/ca_effects/sound.lua")

View File

@ -1,102 +0,0 @@
-- initialize API interface
local api = {}
-- define various standard effect cycle lengths
api.SHORT_CYCLE = 0 -- for particles and fast animations (use GSCYCLE)
api.DEFAULT_CYCLE = 2.0 -- for most effect types
api.LONG_CYCLE = 5.0 -- for ressource intensive tasks or timed effects
-- register new weather presets (like rain)
-- @param name <string> Unique preset name, ideally prefixed
-- @param conditions <table> A collection of required influences
-- @param effects <table> A <table> containing all applied effects as keys and parameters as values
function api.register_weather(name, conditions, effects)
climate_mod.weathers[name] = {
conditions = conditions,
effects = effects,
active_players = {}
}
end
-- register new weather effects (like particles)
-- @param name <string> Unique effect name, ideally prefixed
-- @param handler <function> A function to be called when the effect is active
-- @param htype <string: start|tick|stop> Determines when the function is called
function api.register_effect(name, handler, htype)
-- check for valid handler types
if htype ~= "start" and htype ~= "tick" and htype ~= "stop" then
minetest.log("warning", "[Climate API] Effect " .. dump(name) .. " uses invalid callback type: " .. dump(htype))
return
end
-- create effect handler registry if not existent yet
if type(climate_mod.effects[name]) == "nil" then
climate_mod.effects[name] = { start = {}, tick = {}, stop = {} }
climate_mod.cycles[name] = { timespan = api.DEFAULT_CYCLE, timer = 0 }
end
-- store effect handler
table.insert(climate_mod.effects[name][htype], handler)
end
-- set cycle length of given effect
-- @param name <string> Name of the affected effect
-- @param cycle <number> Duration between function calls
function api.set_effect_cycle(name, cycle)
climate_mod.cycles[name].timespan = cycle
end
-- register new environment influence that is independent of position
-- @param name <string> Unique influence name
-- @param func <function> Returns current influence value for entire world
function api.register_global_influence(name, func)
climate_mod.global_influences[name] = func
end
-- register new environment influence based on position
-- @param name <string> Unique influence name
-- @param func <function> Returns current influence value for given position
function api.register_influence(name, func)
climate_mod.influences[name] = func
end
-- register new Active Block Modifier dependent on weather status
-- Uses same config as Minetest.register_abm() but also adds
-- conditions similiar to weather presets and provides local environment
-- to action event handler as third parameter.
-- @param config <table> ABM configuration with additional information
function api.register_abm(config)
if not climate_mod.settings.block_updates then return end
local conditions = config.conditions
local action = config.action
local pos_override = config.pos_override
-- override action handler to inject weather status
local override = function(pos, node)
if type(pos_override) == "function" then
pos = pos_override(pos)
node = minetest.get_node(pos)
end
-- get environment influences for current position
local env = climate_mod.trigger.get_position_environment(pos)
if conditions == nil then
return action(pos, node, env)
end
-- check if all conditions are met
for condition, goal in pairs(conditions) do
local is_applicable = climate_mod.trigger.test_condition(condition, env, goal)
if not is_applicable then return end
end
return action(pos, node, env)
end
-- register overridden abm setup
config.conditions = nil
config.action = override
minetest.register_abm(config)
end
-- return supplied API endpoint
return api

View File

@ -1,38 +0,0 @@
local mod_player_monoids = minetest.get_modpath("player_monoids") ~= nil
local mod_playerphysics = minetest.get_modpath("playerphysics") ~= nil
local mod_pova = minetest.get_modpath("pova") ~= nil
local utility = {}
function utility.rangelim(value, min, max)
return math.min(math.max(value, min), max)
end
-- from https://stackoverflow.com/a/29133654
-- merges two tables together
-- if in conflict, b will override values of a
function utility.merge_tables(a, b)
if type(a) == "table" and type(b) == "table" then
for k,v in pairs(b) do
if type(v)=="table" and type(a[k] or false)=="table" then
utility.merge_tables(a[k],v)
else a[k]=v end
end
end
return a
end
-- see https://en.wikipedia.org/wiki/Logistic_function
function utility.sigmoid(value, max, growth, midpoint)
return max / (1 + math.exp(-growth * (value - midpoint)))
end
-- generates a wave of cycle length 1
-- maps parameters to values between 0 and 1
-- 0 is mapped to 0 and 0.5 to 1
function utility.normalized_cycle(value)
return math.cos((2 * value + 1) * math.pi) / 2 + 0.5
end
return utility

View File

@ -1,232 +0,0 @@
local S = climate_mod.i18n
-- parse heat values into readable format
-- also convert to Celsius if configured
local function parse_heat(heat)
local indicator = "°F"
if not climate_mod.settings.fahrenheit then
heat = (heat - 32) * 5 / 9
indicator = "°C"
end
heat = math.floor(heat * 100) / 100
return heat .. indicator
end
-- register weather privilege in order to modify the weather status
minetest.register_privilege("weather", {
description = S("Make changes to the current weather"),
give_to_singleplayer = false
})
-- display general information on current weather
minetest.register_chatcommand("weather", {
description = S("Display weather information"),
func = function(playername)
local player = minetest.get_player_by_name(playername)
local ppos = player:get_pos()
local weathers = climate_api.environment.get_weather_presets(player)
local effects = climate_api.environment.get_effects(player)
local heat = climate_api.environment.get_heat(ppos)
local humidity = math.floor(climate_api.environment.get_humidity(ppos) * 100) / 100
local msg = ""
if #weathers > 0 then
msg = msg .. S("The following weather presets are active for you:") .. " "
for _, weather in ipairs(weathers) do
msg = msg .. weather .. ", "
end
msg = msg:sub(1, #msg-2) .. "\n"
else
msg = msg .. S("Your sky is clear. No weather presets are currently active.") .. "\n"
end
if #effects > 0 then
msg = msg .. S("As a result, the following environment effects are applied:") .. " "
for _, effect in ipairs(effects) do
msg = msg .. effect .. ", "
end
msg = msg:sub(1, #msg-2) .. "\n"
end
local heat_desc
if heat > 80 then heat_desc = S("scorching")
elseif heat > 50 then heat_desc = S("pleasant")
else heat_desc = S("chilly") end
msg = msg .. S("It is a @1 @2 right now and humidity is at @3%.", heat_desc, parse_heat(heat), humidity) .. "\n"
minetest.chat_send_player(playername, msg)
end
})
-- set base heat to increase or decrease global climate temperatures
minetest.register_chatcommand("set_base_heat", {
params = "<heat>",
description = S("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, S("Provide a number to modify the base heat"))
return
end
if param == "auto" then param = 0 end
climate_mod.settings.heat = tonumber(param) or 0
minetest.chat_send_player(playername, S("Base heat changed"))
end
})
-- override global heat levels with given value
minetest.register_chatcommand("set_heat", {
params = "<heat>",
description = S("Override the weather algorithm's heat"),
privs = { weather = true },
func = function(playername, param)
if param == nil or param == "" then
minetest.chat_send_player(playername, S("Provide a number to modify the heat"))
return
end
if param == "auto" then
climate_mod.forced_enviroment.heat = nil
minetest.chat_send_player(playername, S("Heat value reset"))
else
climate_mod.forced_enviroment.heat = tonumber(param) or 0
minetest.chat_send_player(playername, S("Heat value changed"))
end
end
})
-- set base heat to increase or decrease global climate humidity
minetest.register_chatcommand("set_base_humidity", {
params = "<humidity>",
description = S("Override the weather algorithm's base humidity"),
privs = { weather = true },
func = function(playername, param)
if param == "auto" then param = 0 end
if param == nil or param == "" then
minetest.chat_send_player(playername, S("Provide a number to modify the base humidity"))
return
end
climate_mod.settings.humidity = tonumber(param) or 0
minetest.chat_send_player(playername, S("Base humidity changed"))
end
})
-- override global humidity with given value
minetest.register_chatcommand("set_humidity", {
params = "<humidity>",
description = S("Override the weather algorithm's humidity"),
privs = { weather = true },
func = function(playername, param)
if param == nil or param == "" then
minetest.chat_send_player(playername, S("Provide a number to modify the humidity"))
return
end
if param == "auto" then
climate_mod.forced_enviroment.humidity = nil
minetest.chat_send_player(playername, S("Humidity value reset"))
else
climate_mod.forced_enviroment.humidity = tonumber(param) or 0
minetest.chat_send_player(playername, S("Humidity value changed"))
end
end
})
-- override wind direction and speed with given values
minetest.register_chatcommand("set_wind", {
params = "<wind>",
description = S("Override the weather algorithm's windspeed"),
privs = { weather = true },
func = function(playername, param)
if param == nil or param == "" then
minetest.chat_send_player(playername, S("Provide a vector of two numbers to modify the wind"))
return
end
local arguments = {}
for w in param:gmatch("%S+") do table.insert(arguments, w) end
local arg1 = arguments[1]
local wind_x = tonumber(arguments[1])
local wind_z = tonumber(arguments[2])
if arg1 == "auto" then
climate_mod.forced_enviroment.wind = nil
minetest.chat_send_player(playername, S("Wind reset"))
elseif wind_x == nil or wind_z == nil then
minetest.chat_send_player(playername, S("Invalid wind configuration"))
else
climate_mod.forced_enviroment.wind = vector.new({
x = wind_x,
y = 0,
z = wind_z
})
minetest.chat_send_player(playername, S("Wind changed"))
end
end
})
-- display current mod config
minetest.register_chatcommand("weather_settings", {
description = S("Print the active Climate API configuration"),
func = function(playername)
minetest.chat_send_player(playername, S("Current Settings") .. "\n================")
for setting, value in pairs(climate_mod.settings) do
minetest.chat_send_player(playername, dump2(value, setting))
end
end
})
-- force a weather preset or disable it
minetest.register_chatcommand("set_weather", {
params ="<weather> <status>",
description = S("Turn the specified weather preset on or off for all players or reset it to automatic"),
privs = { weather = true },
func = function(playername, param)
local arguments = {}
for w in param:gmatch("%S+") do table.insert(arguments, w) end
local weather = arguments[1]
if weather == nil or climate_mod.weathers[weather] == nil then
minetest.chat_send_player(playername, S("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
status = false
elseif arguments[2] == "auto" then
status = nil
else
minetest.chat_send_player(playername, S("Invalid weather status. Set the preset to either on, off or auto."))
return
end
climate_mod.forced_weather[weather] = status
minetest.chat_send_player(playername, S("Weather @1 successfully set to @2", weather, arguments[2]))
end
})
-- list all weather presets and whether they have been forced or disabled
minetest.register_chatcommand("weather_status", {
description = S("Prints which weather presets are enforced or disabled"),
func = function(playername)
minetest.chat_send_player(playername, S("Current activation rules:") .. "\n================")
for weather, _ in pairs(climate_mod.weathers) do
local status = "auto"
if climate_mod.forced_weather[weather] == true then
status = "on"
elseif climate_mod.forced_weather[weather] == false then
status = "off"
end
minetest.chat_send_player(playername, dump2(status, weather))
end
end
})
-- show all environment influences and their values for the executing player
minetest.register_chatcommand("weather_influences", {
description = S("Prints which weather influences cause your current weather"),
func = function(playername)
minetest.chat_send_player(playername, S("Current influences rules:") .. "\n================")
local player = minetest.get_player_by_name(playername)
local influences = climate_mod.trigger.get_player_environment(player)
for influence, value in pairs(influences) do
minetest.chat_send_player(playername, dump2(value, influence))
end
end
})

View File

@ -1,13 +0,0 @@
local state = minetest.get_mod_storage()
if not state:contains("heat_random") then
state:from_table({
heat_random = 1,
humidity_random = 1,
humidity_base = 50,
wind_x = 0.5,
wind_z = 0.5
})
end
return state

View File

@ -1,55 +0,0 @@
local environment = {}
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 = 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");
local random_base = climate_mod.state:get_float("humidity_base");
return (base + biome * 0.7 + random_base * 0.3) * random
end
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")
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)
local pname = player:get_player_name()
local weathers = climate_mod.current_weather[pname]
if type(weathers) == "nil" then weathers = {} end
return weathers
end
function environment.get_effects(player)
local pname = player:get_player_name()
local effects = {}
for effect, players in pairs(climate_mod.current_effects) do
if type(players[pname]) ~= "nil" then
table.insert(effects, effect)
end
end
return effects
end
return environment

View File

@ -1,78 +0,0 @@
climate_api.register_influence("heat",
climate_api.environment.get_heat
)
climate_api.register_influence("base_heat",
minetest.get_heat
)
climate_api.register_influence("humidity",
climate_api.environment.get_humidity
)
climate_api.register_influence("base_humidity",
minetest.get_humidity
)
-- see https://en.wikipedia.org/wiki/Dew_point#Simple_approximation
climate_api.register_influence("dewpoint", function(pos)
local heat = climate_api.environment.get_heat(pos)
local humidity = climate_api.environment.get_humidity(pos)
return heat - (9/25 * (100 - humidity))
end)
climate_api.register_influence("base_dewpoint", function(pos)
local heat = minetest.get_heat(pos)
local humidity = minetest.get_humidity(pos)
return heat - (9/25 * (100 - humidity))
end)
climate_api.register_influence("biome", function(pos)
local data = minetest.get_biome_data(pos)
local biome = minetest.get_biome_name(data.biome)
return biome
end)
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({x = 0, y = 0, z = 0})
if vector.length(wind) == 0 then return 0 end
return minetest.dir_to_yaw(wind)
end)
climate_api.register_influence("height", function(pos)
return pos.y
end)
climate_api.register_influence("light", function(pos)
pos = vector.add(pos, {x = 0, y = 1, z = 0})
return minetest.get_node_light(pos) or 0
end)
climate_api.register_influence("daylight", function(pos)
pos = vector.add(pos, {x = 0, y = 1, z = 0})
return minetest.get_node_light(pos, 0.5) or 0
end)
climate_api.register_influence("indoors", function(pos)
pos = vector.add(pos, {x = 0, y = 1, z = 0})
local daylight = minetest.get_node_light(pos, 0.5) or 0
if daylight < 15 then return true end
for i = 1, climate_mod.settings.ceiling_checks do
local lpos = vector.add(pos, {x = 0, y = i, z = 0})
local node = minetest.get_node_or_nil(lpos)
if node ~= nil and node.name ~= "air" and node.name ~= "ignore" then
return true
end
end
return false
end)
climate_api.register_global_influence("time",
minetest.get_timeofday
)

View File

@ -1,50 +0,0 @@
local GSCYCLE = 0.03 * climate_mod.settings.tick_speed -- only process event loop after this amount of time
local WORLD_CYCLE = 30.00 * climate_mod.settings.tick_speed -- only update global environment influences after this amount of time
local function is_connected(playername)
local connected = minetest.get_connected_players()
for _, player in ipairs(connected) do
local name = player:get_player_name()
if playername == name then return true end
end
return false
end
local gs_timer = 0
local world_timer = 0
minetest.register_globalstep(function(dtime)
gs_timer = gs_timer + dtime
world_timer = world_timer + dtime
if gs_timer + dtime < GSCYCLE then return else gs_timer = 0 end
if world_timer >= WORLD_CYCLE then
world_timer = 0
climate_mod.world.update_status(minetest.get_gametime())
climate_mod.global_environment = climate_mod.trigger.get_global_environment()
end
local previous_effects = table.copy(climate_mod.current_effects)
-- skip weather changes for offline players
for effect, data in pairs(previous_effects) do
for playername, _ in pairs(data) do
if not is_connected(playername) then
previous_effects[effect][playername] = nil
end
end
end
local current_effects = climate_mod.trigger.get_active_effects()
for name, effect in pairs(climate_mod.effects) do
local cycle = climate_mod.cycles[name].timespan * climate_mod.settings.tick_speed
if cycle < climate_mod.cycles[name].timer + dtime then
climate_mod.cycles[name].timer = 0
climate_mod.current_effects[name] = current_effects[name]
climate_mod.trigger.call_handlers(name, current_effects[name], previous_effects[name])
else
climate_mod.cycles[name].timer = climate_mod.cycles[name].timer + dtime
end
end
end)

View File

@ -1,87 +0,0 @@
local mod_player_monoids = minetest.get_modpath("player_monoids") ~= nil
local mod_playerphysics = minetest.get_modpath("playerphysics") ~= nil
local mod_pova = minetest.get_modpath("pova") ~= nil
local physics = {}
-- use player monoids if available
if mod_player_monoids then
function physics.add(id, player, effect, value)
player_monoids[effect]:add_change(player, value, id)
end
function physics.remove(id, player, effect)
player_monoids[effect]:del_change(player, id)
end
-- fallback to playerphysics if available
elseif mod_playerphysics then
function physics.add(id, player, effect, value)
playerphysics.add_physics_factor(player, effect, id, value)
end
function physics.remove(id, player, effect)
playerphysics.remove_physics_factor(player, effect, id)
end
-- fallback to pova if available
-- pova uses additive effect modifiers
-- this tries to simulate multiplication
-- by including the default value in modifier calculation
elseif mod_pova then
function physics.add(id, player, effect, value)
local playername = player:get_player_name()
local defaults = pova.get_override(playername, "default")
local default
if defaults == nil or defaults[effect] == nil then default = 1
else default = defaults[effect] end
local override = {}
override[effect] = (value * default) - default
pova.add_override(playername, id, override)
pova.do_override(player)
end
function physics.remove(id, player, effect)
local playername = player:get_player_name()
pova.del_override(playername, id)
pova.do_override(player)
end
-- fallback to vanilla override as last resort
else
local function apply_physics(player)
local playername = player:get_player_name()
local override = { speed = 1, jump = 1, gravity = 1 }
for effect, modifiers in pairs(physics[playername]) do
override[effect] = 1
for _, modifier in pairs(modifiers) do
override[effect] = override[effect] * modifier
end
end
player:set_physics_override(override)
end
function physics.add(id, player, effect, value)
local playername = player:get_player_name()
if physics[playername] == nil then physics[playername] = {} end
if physics[playername][effect] == nil then physics[playername][effect] = {} end
physics[playername][effect][id] = value
apply_physics(player)
end
function physics.remove(id, player, effect)
local playername = player:get_player_name()
if physics[playername] == nil then return end
if physics[playername][effect] == nil then return end
if physics[playername][effect][id] == nil then return end
physics[playername][effect][id] = nil
apply_physics(player)
end
minetest.register_on_leaveplayer(function(player)
local playername = player:get_player_name()
physics[playername] = nil
end)
end
return physics

View File

@ -1,109 +0,0 @@
local default_sky = {
sky_data = {
base_color = nil,
type = "regular",
textures = nil,
clouds = true,
sky_color = {
day_sky = "#8cbafa",
day_horizon = "#9bc1f0",
dawn_sky = "#b4bafa",
dawn_horizon = "#bac1f0",
night_sky = "#006aff",
night_horizon = "#4090ff",
indoors = "#646464",
fog_tint_type = "default"
}
},
cloud_data = {
density = 0.4,
color = "#fff0f0e5",
ambient = "#000000",
height = 120,
thickness = 16,
speed = {x=0, z=-2}
},
sun_data = {
visible = true,
texture = "sun.png",
tonemap = "sun_tonemap.png",
sunrise = "sunrisebg.png",
sunrise_visible = true,
scale = 1
},
moon_data = {
visible = true,
texture = "moon.png",
tonemap = "moon_tonemap.png",
scale = 1
},
star_data = {
visible = true,
count = 1000,
star_color = "#ebebff69",
scale = 1
}
}
local skybox = {}
local layers = {}
-- from https://stackoverflow.com/a/29133654
-- merges two tables together
-- if in conflict, b will override values of a
local function merge_tables(a, b)
if type(a) == "table" and type(b) == "table" then
for k,v in pairs(b) do
if type(v)=="table" and type(a[k] or false)=="table" then
merge_tables(a[k],v)
else a[k]=v end
end
end
return a
end
local function set_skybox(playername, sky)
local player = minetest.get_player_by_name(playername)
if player == nil or not player.get_stars then return end
player:set_sky(sky.sky_data)
player:set_clouds(sky.cloud_data)
player:set_moon(sky.moon_data)
player:set_sun(sky.sun_data)
player:set_stars(sky.star_data)
end
function skybox.update(playername)
local p_layers = layers[playername]
local sky = table.copy(default_sky)
if p_layers == nil then p_layers = {} end
local numbered_layers = {}
for layer, values in pairs(p_layers) do
table.insert(numbered_layers, values)
end
table.sort(numbered_layers, function(left, right)
if left.priority == nil then left.priority = 1 end
if right.priority == nil then right.priority = 1 end
return left.priority < right.priority
end)
for i = 1, #numbered_layers do
sky = merge_tables(sky, numbered_layers[i])
end
set_skybox(playername, sky)
end
function skybox.add(playername, name, sky)
if layers[playername] == nil then layers[playername] = {} end
layers[playername][name] = sky
end
function skybox.remove(playername, name)
if layers[playername] == nil or layers[playername][name] == nil then return end
layers[playername][name] = nil
end
minetest.register_on_leaveplayer(function(player)
local playername = player:get_player_name()
layers[playername] = nil
end)
return skybox

View File

@ -1,57 +0,0 @@
local soundloop = {}
local sounds = {}
local function parse_sound(sound)
if type(sound) == "string" then
return { name = sound, gain = 1, pitch = 1 }
end
if sound.gain == nil then sound.gain = 1 end
if sound.pitch == nil then sound.pitch = 1 end
return sound
end
soundloop.play = function(player, sound, fade)
sound = parse_sound(sound)
if fade == nil then fade = 1 end
local step
local handle
local start_gain
if sounds[player] == nil then sounds[player] = {} end
if sounds[player][sound.name] == nil then
step = sound.gain / fade
start_gain = 0
elseif sounds[player][sound.name] ~= sound.gain then
minetest.sound_stop(sounds[player][sound.name].handle)
start_gain = sounds[player][sound.name].gain
local change = sound.gain - start_gain
step = change / fade
else
return
end
handle = minetest.sound_play(sound.name, {
to_player = player,
loop = true,
gain = 0
})
sounds[player][sound.name] = {
gain = sound.gain,
handle = handle
}
minetest.sound_fade(handle, step, sound.gain)
return handle
end
soundloop.stop = function(player, sound, fade)
sound = parse_sound(sound)
if sounds[player] == nil or sounds[player][sound.name] == nil then
return
end
if fade == nil then fade = 1 end
local handle = sounds[player][sound.name].handle
local step = -sounds[player][sound.name].gain / fade
minetest.sound_fade(handle, step, 0)
sounds[player][sound.name].gain = 0
minetest.after(fade, minetest.sound_stop, handle)
end
return soundloop

View File

@ -1,175 +0,0 @@
local trigger = {}
function trigger.get_global_environment()
local env = {}
for influence, func in pairs(climate_mod.global_influences) do
env[influence] = func()
end
return env
end
function trigger.get_position_environment(pos)
local env = table.copy(climate_mod.global_environment)
for influence, func in pairs(climate_mod.influences) do
env[influence] = func(pos)
end
return env
end
function trigger.get_player_environment(player)
local ppos = player:get_pos()
if ppos == nil then return end
local env = trigger.get_position_environment(ppos)
env.player = player
return env
end
function trigger.test_condition(condition, env, goal)
local value = env[condition:sub(5)]
if condition:sub(1, 4) == "min_" then
return value ~= nil and goal <= value
elseif condition:sub(1, 4) == "max_" then
return value ~= nil and goal > value
elseif condition:sub(1, 4) == "has_" then
if value == nil then return false end
for _, g in ipairs(goal) do
if value == g then return true end
end
return false
elseif condition:sub(1, 4) == "not_" then
if value == nil then return true end
if type(goal) ~= "table" then
return value ~= goal
end
for _, g in ipairs(goal) do
if value == g then return false end
end
return true
else
value = env[condition]
return type(value) == "nil" or goal == value
end
end
local function is_weather_active(player, weather, env)
if climate_mod.forced_weather[weather] ~= nil then
return climate_mod.forced_weather[weather]
end
local config = climate_mod.weathers[weather]
if type(config.conditions) == "function" then
return config.conditions(env)
end
for condition, goal in pairs(config.conditions) do
if not trigger.test_condition(condition, env, goal) then
return false
end
end
return true
end
local function get_weather_effects(player, weather_config, env)
local config = {}
local effects = {}
if type(weather_config.effects) == "function" then
config = weather_config.effects(env)
else
config = weather_config.effects
end
for effect, value in pairs(config) do
if climate_mod.effects[effect] ~= nil then
effects[effect] = value
end
end
return effects
end
function trigger.get_active_effects()
local environments = {}
for _, player in ipairs(minetest.get_connected_players()) do
local playername = player:get_player_name()
local hp = player:get_hp()
-- skip weather presets for dead players
if hp ~= nil and hp > 0 then
environments[playername] = trigger.get_player_environment(player)
end
end
local effects = {}
climate_mod.current_weather = {}
for wname, wconfig in pairs(climate_mod.weathers) do
for _, player in ipairs(minetest.get_connected_players()) do
local pname = player:get_player_name()
local env = environments[pname]
if env ~= nil then
if is_weather_active(player, wname, env) then
if climate_mod.current_weather[pname] == nil then
climate_mod.current_weather[pname] = {}
end
table.insert(climate_mod.current_weather[pname], wname)
local player_effects = get_weather_effects(player, wconfig, env)
for effect, value in pairs(player_effects) do
if type(effects[effect]) == "nil" then
effects[effect] = {}
end
if type(effects[effect][pname]) == "nil" then
effects[effect][pname] = {}
end
effects[effect][pname][wname] = value
end
end
end
end
end
return effects
end
function trigger.call_handlers(name, effect, prev_effect)
if effect == nil then effect = {} end
if prev_effect == nil then prev_effect = {} end
local starts = {}
local has_starts = false
local ticks = {current = {}, prev = {}}
local has_ticks = false
local stops = {}
local has_stops = false
for player, sources in pairs(effect) do
if type(prev_effect[player]) ~= "nil" then
has_ticks = true
ticks.current[player] = sources
ticks.prev[player] = prev_effect[player]
else
has_starts = true
starts[player] = sources
end
end
for player, sources in pairs(prev_effect) do
if type(effect[player]) == "nil" then
stops[player] = sources
has_stops = true
end
end
if has_starts then
for _, handler in ipairs(climate_mod.effects[name]["start"]) do
handler(starts)
end
end
if has_ticks then
for _, handler in ipairs(climate_mod.effects[name]["tick"]) do
handler(ticks.current, ticks.prev)
end
end
-- remaining table lists ending effects
if has_stops then
for _, handler in ipairs(climate_mod.effects[name]["stop"]) do
handler(stops)
end
end
end
return trigger

View File

@ -1,100 +0,0 @@
local world = {}
local BASE_TIME = 0.2 * climate_mod.settings.time_spread
local WIND_SPREAD = 600
local WIND_SCALE = 2
local HEAT_SPREAD = 400
local HEAT_SCALE = 0.3
local HUMIDITY_SPREAD = 150
local HUMIDITY_SCALE = 0.5
local HUMIDITY_BASE_SPREAD = 800
local HUMIDITY_BASE_SCALE = 40
local nobj_wind_x
local nobj_wind_z
local nobj_heat
local nobj_humidity
local nobj_humidity_base
local pn_wind_speed_x = {
offset = 0,
scale = WIND_SCALE,
spread = {x = WIND_SPREAD, y = WIND_SPREAD, z = WIND_SPREAD},
seed = 31441,
octaves = 2,
persist = 0.5,
lacunarity = 2
}
local pn_wind_speed_z = {
offset = 0,
scale = WIND_SCALE,
spread = {x = WIND_SPREAD, y = WIND_SPREAD, z = WIND_SPREAD},
seed = 938402,
octaves = 2,
persist = 0.5,
lacunarity = 2
}
local pn_heat = {
offset = 1,
scale = HEAT_SCALE,
spread = {x = HEAT_SPREAD, y = HEAT_SPREAD, z = HEAT_SPREAD},
seed = 235896,
octaves = 2,
persist = 0.5,
lacunarity = 2
}
local pn_humidity = {
offset = 0,
scale = HUMIDITY_SCALE,
spread = {x = HUMIDITY_SPREAD, y = HUMIDITY_SPREAD, z = HUMIDITY_SPREAD},
seed = 8374061,
octaves = 2,
persist = 0.5,
lacunarity = 2
}
local pn_humidity_base = {
offset = 50,
scale = HUMIDITY_BASE_SCALE,
spread = {x = HUMIDITY_BASE_SPREAD, y = HUMIDITY_BASE_SPREAD, z = HUMIDITY_BASE_SPREAD},
seed = 3803465,
octaves = 2,
persist = 0.5,
lacunarity = 2
}
local function update_wind(timer)
nobj_wind_x = nobj_wind_x or minetest.get_perlin(pn_wind_speed_x)
nobj_wind_z = nobj_wind_z or minetest.get_perlin(pn_wind_speed_z)
local n_wind_x = nobj_wind_x:get_2d({x = timer, y = 0})
local n_wind_z = nobj_wind_z:get_2d({x = timer, y = 0})
climate_mod.state:set_float("wind_x", n_wind_x)
climate_mod.state:set_float("wind_z", n_wind_z)
end
local function update_heat(timer)
nobj_heat = nobj_heat or minetest.get_perlin(pn_heat)
local n_heat = nobj_heat:get_2d({x = timer, y = 0})
climate_mod.state:set_float("heat_random", n_heat)
end
local function update_humidity(timer)
nobj_humidity = nobj_humidity or minetest.get_perlin(pn_humidity)
local n_humidity = nobj_humidity:get_2d({x = timer, y = 0})
climate_mod.state:set_float("humidity_random", n_humidity)
nobj_humidity_base = nobj_humidity_base or minetest.get_perlin(pn_humidity_base)
local n_humidity_base = nobj_humidity_base:get_2d({x = timer, y = 0})
climate_mod.state:set_float("humidity_base", n_humidity_base)
end
function world.update_status(timer)
timer = math.floor(timer * BASE_TIME)
update_wind(timer)
update_heat(timer)
update_humidity(timer)
end
return world

View File

@ -1,39 +0,0 @@
# textdomain:climate_api
Make changes to the current weather=Ändere das aktuelle Wetter
Display weather information=Betrachte Informationen zum Wetter
The following weather presets are active for you:=Die folgenden Wetterklassen sind gerade aktiv
Your sky is clear. No weather presets are currently active.=Der Himmel ist klar. Es sind keine Wetterklassen aktiv.
As a result, the following environment effects are applied:=Deshalb werden die folgenden Umwelt-Effekte dargestellt:
scorching=stechend heiße
pleasant=angenehme
chilly=kühle
It is a @1 @2 right now and humidity is at @3%.=Es sind gerade @1 @2 und die Luftfeuchtigkeit liegt bei @3%.
Override the weather algorithm's base heat=Überschreibe die Standard-Temperatur
Provide a number to modify the base heat=Gebe eine Zahl an, um die Standard-Temperatur anzupassen
Base heat changed=Die Standard-Temperatur wurde geändert
Override the weather algorithm's heat=Überschreibe die tatsächliche Temperatur
Provide a number to modify the heat=Gebe eine Zahl an, um die Temperatur anzupassen
Heat value reset=Die Temperatur wurde zurückgesetzt
Heat value changed=Die Temperatur wurde geändert
Override the weather algorithm's base humidity=Überschreibe die Standard-Luftfeuchtigkeit
Provide a number to modify the base humidity=Gebe eine Zahl an, um die Standard-Temperatur anzupassen
Base humidity changed=Die Standard-Luftfeuchtigkeit wurde geändert
Override the weather algorithm's humidity=Überschreibe die tatsächliche Luftfeuchtigkeit
Provide a number to modify the humidity=Gebe eine Zahl an, um die Luftfeuchtigkeit anzupassen
Humidity value reset=Die Luftfeuchtigkeit wurde zurückgesetzt
Humidity value changed=Die Luftfeuchtigkeit wurde geändert
Override the weather algorithm's windspeed=Überschreibe die Windgeschwindigkeit
Provide a vector of two numbers to modify the wind=Gebe einen Vektor aus zwei Zahlen an, um die Windgeschwindigkeit anzupassen
Wind reset=Der Wind wurde zurückgesetzt
Invalid wind configuration=Fehlerhafte Windkonfiguration
Wind changed=Der Wind wurde geändert
Print the active Climate API configuration=Betrachte die Einstellungen für Climate API
Current Settings=Aktuelle Einstellungen
Turn the specified weather preset on or off for all players or reset it to automatic=Schalte für alle Spieler die angegebene Wetterklasse an, aus oder schalte sie auf automatisch
Unknown weather preset=Unbekannte Wetterklasse
Invalid weather status. Set the preset to either on, off or auto.=Unbekannter Status. Setze die Wetterklasse entweder auf on, off oder auto
Weather @1 successfully set to @2=Wetter @1 wurde erfolgreich auf @2 gesetzt
Prints which weather presets are enforced or disabled=Betrachte, welche Wetterklassen erzwungen oder deaktiviert sind
Current activation rules:=Aktuelle Aktivierungsregeln
Prints which weather influences cause your current weather=Betrachte, welche Umwelteinflüsse das aktuelle Wetter hervorrufen
Current influences rules:=Aktuelle Einflussfaktoren

View File

@ -1,39 +0,0 @@
# textdomain:climate_api
Make changes to the current weather=
Display weather information=
The following weather presets are active for you:=
Your sky is clear. No weather presets are currently active.=
As a result, the following environment effects are applied:=
scorching=
pleasant=
chilly=
It is a @1 @2 right now and humidity is at @3%.=
Override the weather algorithm's base heat=
Provide a number to modify the base heat=
Base heat changed=
Override the weather algorithm's heat=
Provide a number to modify the heat=
Heat value reset=
Heat value changed=
Override the weather algorithm's base humidity=
Provide a number to modify the base humidity=
Base humidity changed=
Override the weather algorithm's humidity=
Provide a number to modify the humidity=
Humidity value reset=
Humidity value changed=
Override the weather algorithm's windspeed=
Provide a vector of two numbers to modify the wind=
Wind reset=
Invalid wind configuration=
Wind changed=
Print the active Climate API configuration=
Current Settings=
Turn the specified weather preset on or off for all players or reset it to automatic=
Unknown weather preset=
Invalid weather status. Set the preset to either on, off or auto.=
Weather @1 successfully set to @2=
Prints which weather presets are enforced or disabled=
Current activation rules:=
Prints which weather influences cause your current weather=
Current influences rules:=

View File

@ -1,17 +0,0 @@
name = climate_api
title = Climate API
author = TestificateMods
release = 10001
optional_depends = player_monoids, playerphysics, pova
description = """
A powerful engine for weather presets and visual effects.
Use the regional climate to set up different effects for different regions.
Control where your effects are activated based on temperature, humidity, wind,
position, light level or a completely custom activator.
Climate API provides temperature and humidity values on a block-per-block basis
that follow the seasons, day / night cycle and random changes.
Make it rain, change the sky or poison the player - it's up to you.
Climate API requires additional weather packs in order to function.
Try regional_weather for the best experience.
"""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -1,77 +0,0 @@
[Performance]
# 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.
climate_api_tick_speed (Update speed of weather effects) float 1 0.1 10
# 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
# If set to true, weather packs are allowed to register node update handlers.
# These can be used to dynamically place snow layers, melt ice, or hydrate soil.
climate_api_block_updates (Dynamically modify nodes) bool true
# If set to true, Climate API will factor in wind speed and obstacles to determine damage sources.
# If set to false, a simple check will be used whether the player is outside.
# Only applied if climate_api_damage is also set to true.
climate_api_raycast (Include wind speed in damage checks) bool true
# Increase this number if you notice snow or rain inside large glass domes.
# Decrease this number if you notice lag spikes or overall reduced game performance.
ceiling_checks (Check x nodes on outdoor test) int 10 0 50
[Weather Effects]
# If set to true, dangerous weather presets will damage affected players over time.
climate_api_damage (Cause player damage) bool true
# If set to true, weather effects (like rain) are allowed to render particles.
# Deactivating this feature will prevent some presets from being visible.
# For performance considerations it is recommended to decrease the amount of particles instead.
climate_api_particles (Show particle effects) bool true
# If set to true, weather effects are allowed to modify a player's sky.
# This includes skybox, sun, moon, and clouds (also used for fog effects).
# Running this mod on Minetest 5.1.2 or earlier versions will automatically disable this feature.
climate_api_skybox (Override the skybox) bool true
# If set to true, weather effects are allowed to render an image on top of the gameplay.
# This is usually an optional effect used to increase immersion (like a frozen-over camera in a snow storm).
climate_api_hud_overlay (Display HUD overlays) bool true
[Environment]
# This value will be added to all biome's base temperatures before applying random modifiers.
# Every unit here will increase the global base heat by one degree Fahrenheit.
# Negative values will cool down global base heat respectively.
climate_api_heat_base (Global base temperature) float 0
# This value will be added to all biome's base humidity before applying random modifiers.
# Every unit here will increase the global base humidity by one percent.
# Negative values will dry up global base humidity respectively.
climate_api_humidity_base (Global base humidity) float 0
# This value regulates how quickly environment factors like heat, humidity and wind are changing.
# A value of 2 will double the speed at which weather presets change.
# A value of 0.5 will half the speed respectively.
climate_api_time_spread (Time rate of weather changes) float 1 0.1 10
[Preferences]
# If set to true, temperature information in /weather command will be displayed in Fahrenheit.
climate_api_fahrenheit (Show degrees in Fahrenheit instead of Celsius) bool false
# 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.
climate_api_sound (Play ambient sound loops) bool true
# 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.
climate_api_volume (Volume of sound effects) float 1 0 10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,20 +0,0 @@
name = climate
title = Climates, Seasons and Weather Effects
author = TestificateMods
release = 10001
description = """
The complete weather bundle for any Minetest game.
Not every biome is the same and neither should their weather be.
- Climate API provides temperature and humidity values on a block-per-block basis
that follow the seasons, day / night cycle and random changes.
- Regional Weather controls its effects with the local climate in mind.
- Let lightning strike and get a kick out of thunderstorms
- Moon Phases changes the moon to follow a cycle between eight different phases.
Expect the sky to change every four nights (or configure a custom schedule).
- Use the new wind system to travel across the sea with Sailing Kit.
Or loose control over your boat and drift ashore after a storm.
Use Minetest 5.2.0 or higher for the best experience.
Also, if using Minetest Game, head to settings -> games -> Minetest Game and set "Enable Weather" do disabled.
"""

View File

@ -1,157 +0,0 @@
### GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the
terms and conditions of version 3 of the GNU General Public License,
supplemented by the additional permissions listed below.
#### 0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the
GNU General Public License.
"The Library" refers to a covered work governed by this License, other
than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
#### 1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
#### 2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
- a) under this License, provided that you make a good faith effort
to ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
- b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
#### 3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a
header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
- a) Give prominent notice with each copy of the object code that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the object code with a copy of the GNU GPL and this
license document.
#### 4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken
together, effectively do not restrict modification of the portions of
the Library contained in the Combined Work and reverse engineering for
debugging such modifications, if you also do each of the following:
- a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the Combined Work with a copy of the GNU GPL and this
license document.
- c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
- d) Do one of the following:
- 0) Convey the Minimal Corresponding Source under the terms of
this License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- 1) Use a suitable shared library mechanism for linking with
the Library. A suitable mechanism is one that (a) uses at run
time a copy of the Library already present on the user's
computer system, and (b) will operate properly with a modified
version of the Library that is interface-compatible with the
Linked Version.
- e) Provide Installation Information, but only if you would
otherwise be required to provide such information under section 6
of the GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the Application
with a modified version of the Linked Version. (If you use option
4d0, the Installation Information must accompany the Minimal
Corresponding Source and Corresponding Application Code. If you
use option 4d1, you must provide the Installation Information in
the manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.)
#### 5. Combined Libraries.
You may place library facilities that are a work based on the Library
side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
- a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities, conveyed under the terms of this License.
- b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
#### 6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
as you received it specifies that a certain numbered version of the
GNU Lesser General Public License "or any later version" applies to
it, you have the option of following the terms and conditions either
of that published version or of any later version published by the
Free Software Foundation. If the Library as you received it does not
specify a version number of the GNU Lesser General Public License, you
may choose any version of the GNU Lesser General Public License ever
published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -1,106 +0,0 @@
# Regional Weather
A weather pack for [__Climate API__](https://github.com/t-affeldt/climate_api) by Till Affeldt (TestificateMods)
![](https://raw.githubusercontent.com/t-affeldt/regional_weather/master/screenshot.webp)
Not every biome is the same and neither should their weather be.
Regional Weather controls its effects with the local climate in mind.
Experience the humid air of the rain forest and harsh desert sandstorms.
## Troubleshooting
Regional Weather depends on [Climate API](https://github.com/t-affeldt/climate_api) in order to function. Generally speaking, most mods should be compatible to it.
If you notice __odd movement speeds__ or jump heights of players, you should check for mods that also modify player physics. Use a compatibility mod like [player_monoids](https://github.com/minetest-mods/player_monoids) or [playerphysics](https://forum.minetest.net/viewtopic.php?t=22172) to get rid of this problem. This requires the conflicting mod to also support the chosen compatibility layer.
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 in Climate API's settings using the ``Override the skybox`` option. 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.
If you experience __performance issues__, the *Performance* section of Climate API's configuration section is a great place to start looking for a solution.
The following mods are recommended to be installed alongside Regional Weather:
- [Climate API](https://github.com/t-affeldt/climate_api) (required): The necessary weather engine that this mod is built upon
- [Moon Phases](https://github.com/t-affeldt/minetest_moon_phase): Complements weather effects with dynamic sky changes and a full moon cycle
- [Sailing Kit](https://github.com/t-affeldt/sailing_kit) (Fork): Uses Climate API's new wind system to sail across the sea.
- [Lightning](https://github.com/minetest-mods/lightning): Adds to heavy rain by enabling additional lightning effects
- [Farming](https://github.com/minetest/minetest_game/tree/master/mods/farming) (as part of MTG) or [Farming Redo](https://forum.minetest.net/viewtopic.php?t=9019): Add farmland and crops to grow food. Farmland wil turn wet during rain effects.
- [Fire](https://github.com/minetest/minetest_game/tree/master/mods/fire) (as part of MTG): Adds fires that can be caused by lightning strikes and other effects and will be extinguished during rain effects.
- [Pedology](https://forum.minetest.net/viewtopic.php?f=11&t=9429) Adds a lot of nodes with dynamic wetness and dryness states.
- [Ambience](https://notabug.org/TenPlus1/ambience): Plays some nice ambient sound effects based on where you are.
For easier installation, you can get a lot of these mods as part of my [Climate Modpack](https://github.com/t-affeldt/climate).
## Configuration Options
You can find all mod configuration options in your Minetest launcher.
Go to ``Settings → All Settings → Mods → regional_weather`` to change them.
Also check out the options inside the ``climate_api`` section for additional configuration options, including performance tweaks and feature switches.
### Features
- ``Place snow layers`` (default true):
If set to true, snow layers will stack up during snowy weather.
- ``Freeze river water`` (default true):
If set to true, river water sources will freeze at low temperatures and melt when it gets warmer again.
This process does not affect regular ice blocks because it adds its own temporary ones.
- ``Place rain puddles`` (default true):
If set to true, water puddles will form during rain or when snow layers have melted.
- ``Hydrate farmland`` (default true):
If set to true, rain will cause dry farmland to turn wet.
Requires *farming* or *farming_redo* mod.
- ``Extinguish fire`` (bool true):
If set to true, fires will be extinguished during rain showers.
Requires *fire* mod.
- ``Wetten pedology nodes`` (default true):
If set to true, rain will wetten or dry nodes from pedology mod.
Requires *pedology* mod.
### World Configuration
- ``Maximum height of weather effects`` (default 120):
No visual effects will be applied above this height.
This value defaults to normal cloud height (120 nodes above sea level).
- ``Minimum height of weather effects`` (default -50):
No visual effects will be applied below this height.
This will prevent unwanted visuals within large underground caves.
- ``Cloud height`` (default 120)
Average height of cloud bases
- ``Cloud height variation`` (default 40)
Maxmial variation of cloud height from base value
## License information
### Source Code
Unless otherwise stated, this source code is written entirely by myself.
You are free to use it under a GNU Lesser General Public License version 3.
You can find respective rights and conditions in the attached [LICENSE](https://github.com/t-affeldt/regional_weather/blob/master/LICENSE.md) file.
The entire source code is available on [Github](https://github.com/t-affeldt/regional_weather).
### Particles
- Hail textures: *CC BY-SA (3.0)* made by me
- Snow flake textures: *CC BY-SA (3.0)* by paramat, found in snowdrift mod at https://github.com/paramat/snowdrift
- Snow composite texture: *CC BY-SA (3.0)* by Cap, created from aforementioned snow flakes by paramat (please credit original artist as well)
- Rain textures: *CC BY-SA (3.0)* by Cap (an original design for this mod)
### Block Textures
- Puddle textures: *CC BY-SA (3.0)* by Cap
- Snow layers and ice block using textures from *default* (not included)
### Sounds
- Heavy Rain sounds: *CC0* by Q.K., taken from mymonths at https://github.com/minetest-mods/mymonths/tree/master/sounds
- Light Rain sounds: *CC BY 3.0* by Arctura from https://freesound.org/people/Arctura/sounds/34065/
- Wind sound: *CC BY (3.0)* by InspectorJ from https://freesound.org/people/InspectorJ/sounds/376415/
- Hail sound: *CC0* by ikayuka from https://freesound.org/people/ikayuka/sounds/240742/
- Puddle footstep sound: *CC0* by swordofkings128 from https://freesound.org/people/swordofkings128/sounds/398032/
### HUD Overlays
- Frost HUD: *CC BY-SA (3.0)* by Cap
- Original texture for sand storm HUD: *CC0* from https://freestocktextures.com/texture/dirty-baking-paper,1202.html, edits by me under *CC0* as well
### Assets in screenshots
- Screenshots and editing: *CC BY-SA (3.0)* by me
- Logos and artwork: *CC BY-SA (3.0)* by Cap
- Lato Font (for the Logo): *OFL* by Łukasz Dziedzic from http://www.latofonts.com/lato-free-fonts/
- Source Sans Pro (for the subtitles): *OFL*, see https://fonts.google.com/specimen/Source+Sans+Pro
- Used texture pack: Polygonia (128px edition) *CC BY-SA (4.0)* by Lokrates. See https://forum.minetest.net/viewtopic.php?f=4&t=19043
### Full License Conditions
- [GNU Lesser General Public License version 4](https://github.com/t-affeldt/regional_weather/blob/master/LICENSE.md)
- [Creative Commons Licenses](https://creativecommons.org/licenses/)
- [SIL Open Font License](https://opensource.org/licenses/OFL-1.1)

View File

@ -1,24 +0,0 @@
if not regional_weather.settings.fire then return end
if not minetest.get_modpath("fire") then return end
climate_api.register_abm({
label = "extinguish fire at high humidity",
nodenames = { "fire:basic_flame" },
neighbors = { "air" },
interval = 10,
chance = 2,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
max_heat = 85,
daylight = 15,
indoors = false
},
action = function (pos, node, env)
minetest.set_node(pos, { name = "air" })
end
})

View File

@ -1,73 +0,0 @@
if not regional_weather.settings.ice
or not minetest.get_modpath("default")
or default.node_sound_glass_defaults == nil
then return end
local BLOCK_NAME = "regional_weather:ice"
local S = regional_weather.i18n
minetest.register_node(BLOCK_NAME, {
description = S("Thin Ice"),
tiles = {"(default_ice.png^[colorize:#ffffff:50)^[opacity:200"},
paramtype = "light",
groups = {
cracky = 3,
cools_lava = 1,
slippery = 3,
dig_immediate = 2,
melts = 1
},
freezemelt = "default:river_water_source",
sounds = default.node_sound_glass_defaults(),
use_texture_alpha = true,
drop = "",
on_destruct = function(pos)
-- asynchronous to avoid destruction loop
minetest.after(0, function(pos)
if minetest.get_node(pos).name ~= "air" then return end
minetest.set_node(pos, { name = "default:river_water_source" })
end, pos)
end
})
climate_api.register_abm({
label = "freeze river water",
nodenames = { "default:river_water_source" },
neighbors = { "air" },
interval = 25,
chance = 3,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
max_heat = 25,
daylight = 15,
indoors = false
},
action = function (pos, node, env)
minetest.set_node(pos, { name = BLOCK_NAME })
end
})
climate_api.register_abm({
label = "unfreeze river water",
nodenames = { BLOCK_NAME },
interval = 25,
chance = 4,
catch_up = true,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 40,
daylight = 15,
indoors = false
},
action = function (pos, node, env)
minetest.set_node(pos, { name = "default:river_water_source" })
end
})

View File

@ -1,29 +0,0 @@
if not regional_weather.settings.pedology
or not minetest.get_modpath("pedology")
then return end
climate_api.register_abm({
label = "wetten or dry pedology nodes",
nodenames = { "group:sucky" },
neighbors = { "air" },
interval = 25,
chance = 30,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 25,
daylight = 15,
indoors = false,
},
action = function (pos, node, env)
local wetness = minetest.get_item_group(node.name, "wet") or 0
if wetness < 2 and env.humidity > 55 then
pedology.wetten(pos)
elseif wetness > 0 and wetness < 3 and env.humidity < 40 then
pedology.dry(pos)
end
end
})

View File

@ -1,155 +0,0 @@
local BLOCK_PREFIX = "regional_weather:puddle_"
local VARIANT_COUNT = 39
local CHECK_DISTANCE = 4
local MAX_AMOUNT = 3
local GROUND_COVERS = {
"group:soil",
"group:stone",
"group:sand",
"group:wood",
"default:permafrost",
"default:permafrost_with_moss",
"default:permafrost_with_stones"
}
local S = regional_weather.i18n
-- clean up puddles if disabled
if not regional_weather.settings.puddles then
-- set all puddle nodes to air
minetest.register_alias("regional_weather:puddle", "air")
for i = 1, VARIANT_COUNT do
for flip = 0, 1 do
local name = BLOCK_PREFIX .. i
if flip == 1 then
name = name .. "_flipped"
end
minetest.register_alias(name, "air")
end
end
-- return air instead of a puddle
function regional_weather.get_random_puddle()
return { name = "air" }
end
-- end puddle execution
return
end
local node_box = {
type = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, -0.49, 0.5 }
}
local apply_water_group
if regional_weather.settings.puddles_water then
apply_water_group = 1
end
for i = 1, VARIANT_COUNT do
for flip = 0, 1 do
local name = BLOCK_PREFIX .. i
local index = i
if i < 10 then index = "0" .. i end
local texture = "weather_puddle_" .. index .. ".png^[opacity:128"
if flip == 1 then
name = name .. "_flipped"
texture = texture .. "^[transformFX"
end
minetest.register_node(name, {
description = S("Puddle"),
tiles = { texture },
drawtype = "nodebox",
pointable = false,
buildable_to = true,
floodable = true,
walkable = false,
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = true,
node_box = node_box,
groups = {
not_in_creative_inventory = 1,
crumbly = 3,
attached_node = 1,
slippery = 1,
flora = 1,
water = apply_water_group,
weather_puddle = 1
},
drop = "",
sounds = {
footstep = {
name = "weather_puddle",
gain = 0.8
}
}
})
end
end
minetest.register_alias("regional_weather:puddle", BLOCK_PREFIX .. "14")
function regional_weather.get_random_puddle()
local index = math.random(1, VARIANT_COUNT)
local rotation = math.random(0, 3) * 90
local flip = math.random(0, 1)
local name = BLOCK_PREFIX .. index
if flip == 1 then
name = name .. "_flipped"
end
local param2 = minetest.dir_to_facedir(minetest.yaw_to_dir(rotation))
return { name = name, param2 = param2 }
end
-- Makes Puddles when raining
climate_api.register_abm({
label = "create rain puddles",
nodenames = GROUND_COVERS,
neighbors = { "air" },
interval = 8,
chance = 150,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
min_heat = 30,
daylight = 15,
indoors = false
},
pos_override = function(pos)
return vector.add(pos, { x = 0, y = 1, z = 0 })
end,
action = function (pos, node, env)
-- only override air nodes
if minetest.get_node(pos).name ~= "air" then return end
-- do not place puddle if area is not fully loaded
if minetest.find_node_near(pos, CHECK_DISTANCE, "ignore") then return end
-- do not place puddle if already enpugh puddles
local pos1 = vector.add(pos, { x = -CHECK_DISTANCE, y = -1, z = -CHECK_DISTANCE })
local pos2 = vector.add(pos, { x = CHECK_DISTANCE, y = 1, z = CHECK_DISTANCE })
local preplaced = minetest.find_nodes_in_area(pos1, pos2, "group:weather_puddle")
if preplaced ~= nil and #preplaced >= MAX_AMOUNT then return end
minetest.set_node(pos, regional_weather.get_random_puddle())
end
})
-- Makes puddles dry up when not raining
climate_api.register_abm({
label = "remove rain puddles",
nodenames = { "group:weather_puddle" },
interval = 25,
chance = 30,
catch_up = true,
action = function (pos, node, env)
minetest.remove_node(pos)
end
})

View File

@ -1,180 +0,0 @@
local BLOCK_PREFIX = "regional_weather:snow_cover_"
local CHECK_DISTANCE = 5
local MAX_AMOUNT = 20
local S = regional_weather.i18n
if not minetest.get_modpath("default")
or default.node_sound_snow_defaults == nil
or not regional_weather.settings.snow then
for i = 1,5 do
minetest.register_alias(BLOCK_PREFIX .. i, "air")
end
return
end
local destruction_handler = function(pos)
pos.y = pos.y - 1
if minetest.get_node(pos).name == "default:dirt_with_snow" then
minetest.set_node(pos, {name = "default:dirt_with_grass"})
end
end
for i = 1,5 do
local node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0.2*i - 0.5, 0.5}
}
minetest.register_node(BLOCK_PREFIX .. i, {
description = S("Snow Cover"),
tiles = { "default_snow.png" },
drawtype = "nodebox",
buildable_to = i < 3,
floodable = true,
walkable = i > 3,
paramtype = "light",
node_box = node_box,
groups = {
not_in_creative_inventory = 1,
crumbly = 3,
falling_node = 1,
snowy = 1,
weather_snow_cover = i
},
sounds = default.node_sound_snow_defaults(),
drop = "default:snow " .. math.ceil(i / 2),
on_construct = function(pos)
pos.y = pos.y - 1
if minetest.get_node(pos).name == "default:dirt_with_grass" then
minetest.set_node(pos, {name = "default:dirt_with_snow"})
end
end,
on_destruct = destruction_handler,
on_flood = destruction_handler
})
end
climate_api.register_abm({
label = "create snow covers",
nodenames = {
"group:soil",
"group:leaves",
"group:stone",
"default:snowblock",
"group:coverable_by_snow"
},
neighbors = { "air" },
interval = 25,
chance = 80,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
max_heat = 30,
not_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
},
daylight = 15,
indoors = false
},
pos_override = function(pos)
return vector.add(pos, { x = 0, y = 1, z = 0 })
end,
action = function (pos, node, env)
-- only override air nodes
if node.name ~= "air" then return end
-- do not place snow if area is not fully loaded
if minetest.find_node_near(pos, CHECK_DISTANCE, "ignore") then return end
-- do not place snow if already enpugh snow
local pos1 = vector.add(pos, { x = -CHECK_DISTANCE, y = -1, z = -CHECK_DISTANCE })
local pos2 = vector.add(pos, { x = CHECK_DISTANCE, y = 1, z = CHECK_DISTANCE })
local preplaced = minetest.find_nodes_in_area(pos1, pos2, "group:weather_snow_cover")
if preplaced ~= nil and #preplaced >= MAX_AMOUNT then return end
minetest.set_node(pos, { name = BLOCK_PREFIX .. "1" })
end
})
if regional_weather.settings.snow_griefing then
climate_api.register_abm({
label = "replace flora with snow covers and stack covers higher",
nodenames = {
"group:flora",
"group:grass",
"group:plant",
"group:weather_snow_cover"
},
neighbors = { "air" },
interval = 25,
chance = 160,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
max_heat = 30,
not_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
},
daylight = 15,
indoors = false
},
action = function (pos, node, env)
local value = minetest.get_item_group(node.name, "weather_snow_cover") or 0
if value == 0 then
-- do not override plants unless marked as buildable_to
local def = minetest.registered_nodes[node.name]
if def == nil or not def.buildable_to then return end
-- do not override plants of the frost_resistance group
local resistance = minetest.get_item_group(node.name, "frost_resistance") or 0
if resistance > 0 then return end
end
-- do not place snow if area is not fully loaded
if minetest.find_node_near(pos, CHECK_DISTANCE, "ignore") then return end
-- do not place snow if already enpugh snow
local pos1 = vector.add(pos, { x = -CHECK_DISTANCE, y = -1, z = -CHECK_DISTANCE })
local pos2 = vector.add(pos, { x = CHECK_DISTANCE, y = 1, z = CHECK_DISTANCE })
local preplaced = minetest.find_nodes_in_area(pos1, pos2, "group:weather_snow_cover")
if preplaced ~= nil and #preplaced >= MAX_AMOUNT then return end
if value < 5 then
minetest.set_node(pos, { name = BLOCK_PREFIX .. (value + 1) })
end
end
})
end
climate_api.register_abm({
label = "melt snow covers",
nodenames = { "group:weather_snow_cover" },
interval = 25,
chance = 85,
catch_up = true,
action = function (pos, node, env)
local value = minetest.get_item_group(node.name, "weather_snow_cover")
if value == nil then value = 0 end
if value > 1 then
minetest.set_node(pos, { name = BLOCK_PREFIX .. (value - 1) })
elseif regional_weather.settings.puddles then
minetest.set_node(pos, regional_weather.get_random_puddle())
else
minetest.set_node(pos, { name = "air" })
end
end
})

View File

@ -1,50 +0,0 @@
if not regional_weather.settings.soil then return end
if not minetest.get_modpath("farming") then return end
if farming ~= nil and farming.mod == "redo" then
climate_api.register_abm({
label = "wetten soil at high humidity",
nodenames = { "farming:soil" },
interval = 8,
chance = 2,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
min_heat = 30,
daylight = 15,
indoors = false
},
action = function (pos, node, env)
minetest.set_node(pos, { name = "farming:soil_wet" })
end
})
else
climate_api.register_abm({
label = "wetten fields at high humidity",
nodenames = { "group:field" },
interval = 8,
chance = 2,
catch_up = false,
conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 55,
min_heat = 30,
daylight = 15,
indoors = false
},
action = function (pos, node, env)
local node_def = minetest.registered_nodes[node.name] or nil
local wet_soil = node_def.soil.wet or nil
if wet_soil == nil then return end
minetest.set_node(pos, { name = wet_soil })
end
})
end

View File

@ -1,62 +0,0 @@
--[[
# Lightning Effect
Use this effect to cause lightning strikes.
Requires lightning mod in order to function. Uses default lightning configuration.
Expects an integer indicating a chance (between 0 and 1) for lightning to strike (per cycle and player).
]]
if not minetest.get_modpath("lightning") then return end
if regional_weather.settings.lightning == 0 then return end
local EFFECT_NAME = "regional_weather:lightning"
lightning.auto = false
local rng = PcgRandom(82492402425)
-- simplified position chooser by Auke Kok (sofar) taken from lightning mod itself
-- see https://github.com/minetest-mods/lightning/blob/master/init.lua#L53-L91
-- "lightning" is licensed under GNU Lesser Public License 2.1 or any later revision
local function choose_pos(pos)
pos.x = math.floor(pos.x - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
pos.y = pos.y + (lightning.range_v / 2)
pos.z = math.floor(pos.z - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
local b, pos2 = minetest.line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
-- nothing but air found
if b then
return nil
end
local n = minetest.get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
if n.name == "air" or n.name == "ignore" then
return nil
end
return pos2
end
local function handle_effect(player_data)
for playername, data in pairs(player_data) do
local chance = 0
for weather, value in pairs(data) do
if type(value) ~= "number" then
value = 1/20
end
chance = chance + value - (chance * value)
end
local random = math.random()
if random <= chance * regional_weather.settings.lightning then
local player = minetest.get_player_by_name(playername)
local ppos = player:get_pos()
local position = choose_pos(ppos)
if position ~= nil then
lightning.strike(position)
end
end
end
end
climate_api.register_effect(EFFECT_NAME, handle_effect, "tick")
climate_api.set_effect_cycle(EFFECT_NAME, climate_api.LONG_CYCLE)

View File

@ -1,31 +0,0 @@
--[[
# Player Speed Effect
Use this effect to modify a player's movement speed.
Expects a numeric value that will be multiplied with the current speed physics.
]]
if not regional_weather.settings.player_speed then return end
local EFFECT_NAME = "regional_weather:speed_buff"
local function handle_effect(player_data)
for playername, data in pairs(player_data) do
local player = minetest.get_player_by_name(playername)
local product = 1
for weather, value in pairs(data) do
product = product * value
end
climate_api.player_physics.add(EFFECT_NAME, player, "speed", product)
end
end
local function remove_effect(player_data)
for playername, data in ipairs(player_data) do
local player = minetest.get_player_by_name(playername)
climate_api.player_physics.remove(EFFECT_NAME, player, "speed")
end
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)

View File

@ -1,66 +0,0 @@
local name = "regional_weather:ambient"
local conditions = {}
-- see https://en.wikipedia.org/wiki/Cloud_base
local function calc_cloud_height(heat, humidity, dewpoint)
local base = regional_weather.settings.cloud_height
-- much lower scale like 20 instead of 1000 fitting for Minetest
local scale = regional_weather.settings.cloud_scale
local spread = heat - dewpoint
local variation = spread / 4.4 * scale * 0.3
return base + climate_api.utility.rangelim(variation, -scale, scale)
end
local function generate_effects(params)
local override = {}
local cloud_height = calc_cloud_height(params.heat, params.humidity, params.dewpoint)
local wind = climate_api.environment.get_wind({ x = 0, y = cloud_height, z = 0 })
local skybox = {priority = 10}
skybox.cloud_data = {
density = climate_api.utility.rangelim(params.humidity / 100, 0.15, 0.65),
speed = wind,
thickness = climate_api.utility.rangelim(params.base_humidity * 0.2, 1, 18),
height = cloud_height,
ambient = "#0f0f1050"
}
if params.height > -100 and params.humidity > 40 then
skybox.cloud_data.color = "#b2a4a4b0"
end
if params.height > -100 and params.humidity > 65 then
skybox.sky_data = {
type = "regular",
clouds = true,
sky_color = {
day_sky = "#6a828e",
day_horizon = "#5c7a8a",
dawn_sky = "#b2b5d7",
dawn_horizon = "#b7bce1",
night_sky = "#2373e1",
night_horizon = "#315d9b"
}
}
skybox.cloud_data.color = "#828e97b5"
skybox.cloud_data.ambient = "#20212250"
end
override["climate_api:skybox"] = skybox
local movement = params.player:get_player_velocity()
local movement_direction
if (vector.length(movement) < 0.1) then
movement_direction = vector.new(0, 0, 0)
else
movement_direction = vector.normalize(movement)
end
local vector_product = vector.dot(movement_direction, wind)
local movement_penalty = climate_api.utility.sigmoid(vector_product, 1.5, 0.15, 0.9) + 0.2
override["regional_weather:speed_buff"] = movement_penalty
return override
end
climate_api.register_weather(name, conditions, generate_effects)

View File

@ -1,24 +0,0 @@
local name = "regional_weather:deep_cave"
local conditions = {
max_daylight = minetest.LIGHT_MAX,
max_height = -100
}
local effects = {}
effects["climate_api:skybox"] = {
sky_data = {
type = "plain",
base_color = { r = 0, g = 0, b = 0 },
clouds = false
},
sun_data = {
visible = false,
sunrise_visible = false
},
moon_data = { visible = false },
star_data = { visible = false },
priority = 100
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,38 +0,0 @@
local name = "regional_weather:fog"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_humidity = 40,
max_humidity = 50,
max_windspeed = 2,
min_heat = 40,
max_heat = 50
}
local effects = {}
effects["climate_api:skybox"] = {
sky_data = {
clouds = true
},
cloud_data = {
density = 1,
color = "#ffffff80",
thickness = 40,
speed = {x=0,y=0,z=0}
},
priority = 50
}
local function generate_effects(params)
local override = {}
override["climate_api:skybox"] = {
cloud_data = {
height = params.player:get_pos().y - 20
}
}
return climate_api.utility.merge_tables(effects, override)
end
climate_api.register_weather(name, conditions, generate_effects)

View File

@ -1,32 +0,0 @@
local name = "regional_weather:fog_heavy"
local conditions = {
min_height = regional_weather.settings.min_height * 0.9,
max_height = regional_weather.settings.max_height * 0.9,
min_humidity = 43,
max_humidity = 47,
max_windspeed = 1.5,
min_heat = 43,
max_heat = 47
}
local effects = {}
effects["climate_api:hud_overlay"] = {
file = "weather_hud_fog.png^[opacity:100",
z_index = -200,
color_correction = true
}
effects["climate_api:skybox"] = {
sky_data = {
type = "plain",
base_color = "#c0c0c08f"
},
cloud_data = {
color = "#ffffffc0",
},
priority = 51
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,55 +0,0 @@
local name = "regional_weather:hail"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 30,
max_heat = 45,
min_humidity = 65,
min_windspeed = 2.5,
indoors = false,
not_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
}
}
local effects = {}
effects["climate_api:damage"] = {
rarity = 15,
value = 3,
check = {
type = "raycast",
height = 7,
velocity = 20
}
}
effects["climate_api:sound"] = {
name = "weather_hail",
gain = 1
}
effects["regional_weather:lightning"] = 1 / 30
local textures = {}
for i = 1,5 do
textures[i] = "weather_hail" .. i .. ".png"
end
effects["climate_api:particles"] = {
boxsize = { x = 18, y = 0, z = 18 },
v_offset = 7,
velocity = 20,
amount = 6,
expirationtime = 0.7,
texture = textures,
glow = 5
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,48 +0,0 @@
local name = "regional_weather:pollen"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 40,
min_humidity = 30,
max_humidity = 40,
max_windspeed = 2,
indoors = false,
has_biome = {
"default",
"deciduous_forest",
"deciduous_forest_ocean",
"deciduous_forest_shore",
"grassland",
"grassland_dunes",
"grassland_ocean",
"snowy_grassland",
"snowy_grassland_ocean",
"grassy",
"grassy_ocean",
"grassytwo",
"grassytwo_ocean",
"mushroom",
"mushroom_ocean",
"plains",
"plains_ocean",
"sakura",
"sakura_ocean"
}
}
local effects = {}
effects["climate_api:particles"] = {
boxsize = { x = 24, y = 0, z = 24 },
vbox = 5,
v_offset = -1,
velocity = -0.1,
acceleration = -0.03,
expirationtime = 5,
size = 0.8,
texture = "weather_pollen.png",
glow = 2
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,31 +0,0 @@
local name = "regional_weather:rain"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 35,
min_humidity = 50,
max_humidity = 65,
indoors = false
}
local effects = {}
effects["climate_api:sound"] = {
name = "weather_rain",
gain = 1.5
}
effects["climate_api:particles"] = {
boxsize = { x = 18, y = 2, z = 18 },
v_offset = 6,
expirationtime = 1.6,
size = 2,
amount = 15,
velocity = 6,
acceleration = 0.05,
texture = "weather_raindrop.png",
glow = 5
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,43 +0,0 @@
local name = "regional_weather:rain_heavy"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 40,
min_humidity = 65,
indoors = false
}
local effects = {}
effects["climate_api:skybox"] = {
cloud_data = {
color = "#5e676eb5"
},
priority = 11
}
effects["climate_api:sound"] = {
name = "weather_rain_heavy",
gain = 1
}
effects["regional_weather:lightning"] = 1 / 20
effects["climate_api:particles"] = {
boxsize = { x = 18, y = 0, z = 18 },
v_offset = 7,
velocity = 7,
amount = 17,
expirationtime = 1.2,
minsize = 25,
maxsize = 35,
texture = {
"weather_rain.png",
"weather_rain.png",
"weather_rain_medium.png"
},
glow = 5
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,87 +0,0 @@
local name = "regional_weather:sandstorm"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_heat = 50,
max_humidity = 25,
min_windspeed = 4.5,
has_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
}
}
local effects = {}
effects["climate_api:hud_overlay"] = {
file = "weather_hud_sand.png",
z_index = -100,
color_correction = true
}
effects["climate_api:damage"] = {
rarity = 3,
value = 1,
check = {
type = "raycast",
height = 0,
velocity = 0.3
}
}
effects["climate_api:particles"] = {
boxsize = { x = 8, y = 4.5, z = 8 },
velocity = 0.6,
acceleration = -0.2,
amount = 12,
expirationtime = 0.7,
size = 25,
texture = {
"weather_sandstorm.png",
"weather_sandstorm.png^[transformFY",
"weather_sandstorm.png^[transformR180",
"weather_sandstorm.png^[transformFYR180"
}
}
effects["climate_api:skybox"] = {
sky_data = {
type = "plain",
clouds = true,
},
cloud_data = {
density = 1,
color = "#f7e4bfc0",
thickness = 40,
speed = {x=0,y=0,z=0}
},
priority = 60
}
local function generate_effects(params)
local override = {}
local light = math.max(params.light / 15, 0.2)
local color = {r = 247 * light, g = 228 * light, b = 191 * light, a = 256}
override["climate_api:skybox"] = {
sky_data = {
base_color = color
},
cloud_data = {
height = params.player:get_pos().y - 20
}
}
override = climate_api.utility.merge_tables(effects, override)
if params.daylight < 15 then
local result = {}
result["climate_api:skybox"] = override["climate_api:skybox"]
return result
end
return override
end
climate_api.register_weather(name, conditions, generate_effects)

View File

@ -1,38 +0,0 @@
local name = "regional_weather:snow"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
max_heat = 35,
min_humidity = 50,
max_humidity = 65,
indoors = false,
not_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
}
}
local effects = {}
local textures = {}
for i = 1,12,1 do
textures[i] = "weather_snowflake" .. i .. ".png"
end
effects["climate_api:particles"] = {
boxsize = { x = 24, y = 6, z = 24 },
v_offset = 2,
amount = 4,
expirationtime = 7,
velocity = 0.85,
acceleration = -0.06,
texture = textures,
glow = 6
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,45 +0,0 @@
local name = "regional_weather:snow_heavy"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
max_heat = 30,
min_humidity = 65,
indoors = false,
not_biome = {
"cold_desert",
"cold_desert_ocean",
"desert",
"desert_ocean",
"sandstone_desert",
"sandstone_desert_ocean"
}
}
local effects = {}
effects["climate_api:skybox"] = {
cloud_data = {
color = "#5e676eb5"
},
priority = 11
}
effects["climate_api:hud_overlay"] = {
file = "weather_hud_frost.png",
z_index = -100,
color_correction = true
}
effects["climate_api:particles"] = {
boxsize = { x = 14, y = 3, z = 14 },
v_offset = 3,
expirationtime = 7.5,
size = 15,
amount = 6,
velocity = 0.75,
texture = "weather_snow.png",
glow = 6
}
climate_api.register_weather(name, conditions, effects)

View File

@ -1,28 +0,0 @@
local name = "regional_weather:storm"
local conditions = {
min_height = regional_weather.settings.min_height,
max_height = regional_weather.settings.max_height,
min_windspeed = 3,
indoors = false,
}
local effects = {}
effects["climate_api:sound"] = {
name = "weather_wind"
}
local function generate_effects(params)
local avg_windspeed = 5
local intensity = params.windspeed / avg_windspeed
local override = {}
override["climate_api:sound"] = {
gain = math.min(intensity, 1.2)
}
return climate_api.utility.merge_tables(effects, override)
end
climate_api.register_weather(name, conditions, generate_effects)

View File

@ -1,71 +0,0 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local function get_setting_bool(name, default, is_global)
local prefix = ""
if not is_global then prefix = "regional_weather_" end
local value = minetest.settings:get_bool(prefix .. name)
if type(value) == "nil" then value = default end
return minetest.is_yes(value)
end
local function get_setting_number(name, default, is_global)
local prefix = ""
if not is_global then prefix = "regional_weather_" end
local value = minetest.settings:get(prefix .. name)
if type(value) == "nil" then value = default end
return tonumber(value)
end
regional_weather = {}
regional_weather.settings = {}
regional_weather.settings.player_speed = get_setting_bool("player_speed", true)
regional_weather.settings.snow = get_setting_bool("snow_layers", true)
regional_weather.settings.snow_griefing = get_setting_bool("snow_griefing", true)
regional_weather.settings.puddles = get_setting_bool("puddles", true)
regional_weather.settings.puddles_water = get_setting_bool("puddles_water", false)
regional_weather.settings.soil = get_setting_bool("soil", true)
regional_weather.settings.fire = get_setting_bool("fire", true)
regional_weather.settings.ice = get_setting_bool("ice", true)
regional_weather.settings.pedology = get_setting_bool("pedology", true)
regional_weather.settings.lightning = get_setting_number("lightning", 1)
regional_weather.settings.max_height = get_setting_number("max_height", 120)
regional_weather.settings.min_height = get_setting_number("min_height", -50)
regional_weather.settings.cloud_height = get_setting_number("cloud_height", 120)
regional_weather.settings.cloud_scale = get_setting_number("cloud_scale", 40)
local S = minetest.get_translator("regional_weather")
regional_weather.i18n = S
-- warn about clouds being overriden by MTG weather
if climate_mod.settings.skybox
and minetest.get_modpath("weather")
and get_setting_bool("enable_weather", true, true) then
minetest.log("warning", "[Regional Weather] " .. S("Disable MTG weather for the best experience. Check the forum for more information."))
end
-- import individual weather types
dofile(modpath.."/ca_weathers/ambient.lua")
dofile(modpath.."/ca_weathers/deep_cave.lua")
dofile(modpath.."/ca_weathers/fog.lua")
dofile(modpath.."/ca_weathers/fog_heavy.lua")
dofile(modpath.."/ca_weathers/hail.lua")
dofile(modpath.."/ca_weathers/pollen.lua")
dofile(modpath.."/ca_weathers/rain.lua")
dofile(modpath.."/ca_weathers/rain_heavy.lua")
dofile(modpath.."/ca_weathers/sandstorm.lua")
dofile(modpath.."/ca_weathers/snow.lua")
dofile(modpath.."/ca_weathers/snow_heavy.lua")
dofile(modpath.."/ca_weathers/storm.lua")
-- register environment effects
dofile(modpath.."/ca_effects/lightning.lua")
dofile(modpath.."/ca_effects/speed_buff.lua")
-- register ABM cycles and custom nodes
dofile(modpath .. "/abms/puddle.lua")
dofile(modpath .. "/abms/snow_cover.lua")
dofile(modpath .. "/abms/fire.lua")
dofile(modpath .. "/abms/ice.lua")
dofile(modpath .. "/abms/pedology.lua")
dofile(modpath .. "/abms/soil.lua")

View File

@ -1,5 +0,0 @@
# textdomain:regional_weather
Disable MTG weather for the best experience. Check the forum for more information.=Deaktiviere MTG weather für die beste Spielerfahrung. Mehr Informationen im Forum.
Thin Ice=Dünnes Eis
Puddle=Pfütze
Snow Cover=Schnee

View File

@ -1,5 +0,0 @@
# textdomain:regional_weather
Disable MTG weather for the best experience. Check the forum for more information.=Deaktiviere MTG weather für die beste Spielerfahrung. Mehr Informationen im Forum.
Thin Ice=Hielo delgado
Puddle=Charco
Snow Cover=Cubierta de nieve

View File

@ -1,5 +0,0 @@
# textdomain:regional_weather
Disable MTG weather for the best experience=
Thin Ice=
Puddle=
Snow Cover=

View File

@ -1,12 +0,0 @@
name = regional_weather
title = Regional Weather
author = TestificateMods
release = 100000
depends = climate_api
optional_depends = default, lightning, farming, fire, pedology
description = """
Not every biome is the same and neither should their weather be.
Regional Weather controls it's effects with the local climate in mind.
Experience the humid air of the rain forest and harsh desert sandstorms.
"""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 MiB

View File

@ -1,50 +0,0 @@
[Features]
# If set to true, wind will boost or penalize player movements based on direction.
regional_weather_player_speed (Change movement speed based on wind) bool true
# If set to true, snow layers will stack up during snowy weather.
regional_weather_snow_layers (Place snow layers) bool true
# If set to true, snow layers will destroy crops
regional_weather_snow_griefing (Destructive snow layers) bool true
# If set to true, river water sources will freeze at low temperatures and melt when it gets warmer again.
# This process does not affect regular ice blocks because it adds its own temporary ones.
regional_weather_ice (Freeze river water) bool true
# If set to true, water puddles will form during rain or when snow layers have melted.
regional_weather_puddles (Place rain puddles) bool true
# If set to true, puddles will be marked as water and hydrate farmland.
# Not compatible with some ambient sound or mob mods
regional_weather_puddles_water (Hydrate farmland near puddles) bool false
# If set to true, rain will cause dry farmland to turn wet.
regional_weather_soil (Hydrate farmland during rain) bool true
# If set to true, fires will be extinguished during rain showers.
regional_weather_fire (Extinguish fire) bool true
# If set to true, rain will wetten or dry nodes from pedology mod.
regional_weather_pedology (Wetten pedology nodes) bool true
# Multiplier for lightning strike chances
# Requires lightning mod to be installed
regional_weather_lightning (Lightning chance modifier) float 1 0 20
[World Configuration]
# No visual effects will be applied below this height.
# This will prevent unwanted visuals within large underground caves.
regional_weather_min_height (Minimum height of weather effects) int -50
# No visual effects will be applied above this height.
# This value defaults to normal cloud height (120 nodes above sea level).
regional_weather_max_height (Maximum height of weather effects) int 120
# Average height of cloud bases
regional_weather_cloud_height (Cloud height) int 120
# Maxmial variation of cloud height from base value
regional_weather_cloud_scale (Cloud height variation) int 40

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Some files were not shown because too many files have changed in this diff Show More