mirror of
https://github.com/t-affeldt/climate_api.git
synced 2024-12-22 17:00:36 +01:00
Fix countless bugs, implement chat commands
This commit is contained in:
parent
fdc457bd09
commit
2090aff6bd
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Climate API
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Assets in screenshots
|
||||||
|
- All screenshots and editing by me: *CC BY-SA (4.0)*
|
||||||
|
- Lato Font (for the Logo): *OFL* by Łukasz Dziedzic from http://www.latofonts.com/lato-free-fonts/
|
||||||
|
- Liberation Fonts (for the text): *OFL*, see https://github.com/liberationfonts/liberation-fonts
|
||||||
|
- Used texture pack: Polygonia (128px edition) *CC BY-SA (4.0)* by Lokrates. See https://forum.minetest.net/viewtopic.php?f=4&t=19043
|
5
TODO.md
5
TODO.md
@ -27,13 +27,16 @@
|
|||||||
- Make switches between effects more smooth
|
- Make switches between effects more smooth
|
||||||
- Adjust size of particle boxes based on player speed
|
- Adjust size of particle boxes based on player speed
|
||||||
- Ability to register environment conditions dynamically (like the heat)
|
- Ability to register environment conditions dynamically (like the heat)
|
||||||
|
- Create conditions for time of day, annual progression, biome filters
|
||||||
|
- Let rain extinguish flames
|
||||||
|
- Ability to force toggle weather presets on / off with chat commands
|
||||||
|
|
||||||
## Future Plans & Ideas
|
## Future Plans & Ideas
|
||||||
- Complete season system
|
- Complete season system
|
||||||
- crops grow better in their respective season or worse in winter
|
- crops grow better in their respective season or worse in winter
|
||||||
- regrowing apples, lemons, etc. in their respective months
|
- regrowing apples, lemons, etc. in their respective months
|
||||||
- holidays and reminders via chat commands
|
- holidays and reminders via chat commands
|
||||||
- day/night nycle adjusted to season
|
- day/night cycle adjusted to season
|
||||||
- special events like a bloodmoon -> increased mob spawns
|
- special events like a bloodmoon -> increased mob spawns
|
||||||
- Fantasy weather effects
|
- Fantasy weather effects
|
||||||
- pretty skyboxes
|
- pretty skyboxes
|
||||||
|
@ -24,12 +24,6 @@ end
|
|||||||
local function handle_effect(player_data)
|
local function handle_effect(player_data)
|
||||||
for playername, data in pairs(player_data) do
|
for playername, data in pairs(player_data) do
|
||||||
local player = minetest.get_player_by_name(playername)
|
local player = minetest.get_player_by_name(playername)
|
||||||
|
|
||||||
local data = player.get_meta()
|
|
||||||
local current_size = data.get_float("climate_api:cloud_size")
|
|
||||||
local current_speed_x = data.get_float("climate_api:cloud_speed_x")
|
|
||||||
local current_speed_z = data.get_float("climate_api:cloud_speed_z")
|
|
||||||
|
|
||||||
local clouds = {}
|
local clouds = {}
|
||||||
for weather, value in pairs(data) do
|
for weather, value in pairs(data) do
|
||||||
clouds.size = accumulate(clouds.size, data.size, function(a, b) return a * b end)
|
clouds.size = accumulate(clouds.size, data.size, function(a, b) return a * b end)
|
||||||
|
14
init.lua
14
init.lua
@ -7,11 +7,15 @@ local modname = minetest.get_current_modname()
|
|||||||
local modpath = minetest.get_modpath(modname)
|
local modpath = minetest.get_modpath(modname)
|
||||||
|
|
||||||
local function getBoolSetting(name, default)
|
local function getBoolSetting(name, default)
|
||||||
return minetest.is_yes(minetest.settings:get_bool("climate_api_" .. name) or default)
|
local value = minetest.settings:get_bool("climate_api_" .. name)
|
||||||
|
if type(value) == "nil" then value = default end
|
||||||
|
return minetest.is_yes(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getNumericSetting(name, default)
|
local function getNumericSetting(name, default)
|
||||||
return tonumber(minetest.settings:get("climate_api_" .. name) or default)
|
local value = minetest.settings:get("climate_api_" .. name)
|
||||||
|
if type(value) == "nil" then value = default end
|
||||||
|
return tonumber(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- load settings from config file
|
-- load settings from config file
|
||||||
@ -21,14 +25,19 @@ climate_mod.settings = {
|
|||||||
sound = getBoolSetting("sound", true),
|
sound = getBoolSetting("sound", true),
|
||||||
wind = getBoolSetting("wind", true),
|
wind = getBoolSetting("wind", true),
|
||||||
seasons = getBoolSetting("seasons", true),
|
seasons = getBoolSetting("seasons", true),
|
||||||
|
fahrenheit = getBoolSetting("fahrenheit", false),
|
||||||
heat = getNumericSetting("heat_base", 0),
|
heat = getNumericSetting("heat_base", 0),
|
||||||
humidity = getNumericSetting("humidity_base", 0),
|
humidity = getNumericSetting("humidity_base", 0),
|
||||||
time_spread = getNumericSetting("time_spread", 1),
|
time_spread = getNumericSetting("time_spread", 1),
|
||||||
particle_count = getNumericSetting("particle_count", 1)
|
particle_count = getNumericSetting("particle_count", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- initiate empty registers
|
||||||
climate_mod.current_weather = {}
|
climate_mod.current_weather = {}
|
||||||
climate_mod.current_effects = {}
|
climate_mod.current_effects = {}
|
||||||
|
climate_mod.weathers = {}
|
||||||
|
climate_mod.effects = {}
|
||||||
|
climate_mod.cycles = {}
|
||||||
|
|
||||||
-- import core API
|
-- import core API
|
||||||
climate_mod.state = dofile(modpath .. "/lib/datastorage.lua")
|
climate_mod.state = dofile(modpath .. "/lib/datastorage.lua")
|
||||||
@ -38,6 +47,7 @@ climate_api.environment = dofile(modpath .. "/lib/environment.lua")
|
|||||||
climate_mod.world = dofile(modpath .. "/lib/world.lua")
|
climate_mod.world = dofile(modpath .. "/lib/world.lua")
|
||||||
climate_mod.trigger = dofile(modpath .. "/lib/trigger.lua")
|
climate_mod.trigger = dofile(modpath .. "/lib/trigger.lua")
|
||||||
dofile(modpath.."/lib/main.lua")
|
dofile(modpath.."/lib/main.lua")
|
||||||
|
dofile(modpath.."/lib/commands.lua")
|
||||||
|
|
||||||
-- import predefined environment effects
|
-- import predefined environment effects
|
||||||
dofile(modpath .. "/ca_effects/particles.lua")
|
dofile(modpath .. "/ca_effects/particles.lua")
|
||||||
|
@ -5,10 +5,6 @@ api.DEFAULT_CYCLE = 0.1 -- for most effect types
|
|||||||
api.MEDIUM_CYCKE = 2.0 -- for ressource intensive tasks
|
api.MEDIUM_CYCKE = 2.0 -- for ressource intensive tasks
|
||||||
api.LONG_CYCLE = 5.0 -- for write operations and skybox changes
|
api.LONG_CYCLE = 5.0 -- for write operations and skybox changes
|
||||||
|
|
||||||
climate_mod.weathers = {}
|
|
||||||
climate_mod.effects = {}
|
|
||||||
climate_mod.cycles = {}
|
|
||||||
|
|
||||||
function api.register_weather(name, conditions, effects)
|
function api.register_weather(name, conditions, effects)
|
||||||
-- TODO: check and sanitize
|
-- TODO: check and sanitize
|
||||||
climate_mod.weathers[name] = {
|
climate_mod.weathers[name] = {
|
||||||
|
89
lib/commands.lua
Normal file
89
lib/commands.lua
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
minetest.register_privilege("weather", {
|
||||||
|
description = "Make changes to the current weather",
|
||||||
|
give_to_singleplayer = false
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("weather", {
|
||||||
|
description ="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 .. "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 .. "Your sky is clear. No weather presets are currently active.\n"
|
||||||
|
end
|
||||||
|
if #effects > 0 then
|
||||||
|
msg = msg .. "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 = "scorching"
|
||||||
|
elseif heat > 50 then heat_desc = "pleasant"
|
||||||
|
else heat_desc = "chilly" end
|
||||||
|
msg = msg .. "It is a " .. heat_desc .. " " .. parse_heat(heat) .. " right now and "
|
||||||
|
msg = msg .. "humidity is at " .. humidity .. "%.\n"
|
||||||
|
minetest.chat_send_player(playername, msg)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("set_heat", {
|
||||||
|
params = "<heat>",
|
||||||
|
description = "Override the weather algorithm's base heat",
|
||||||
|
privs = { weather = true },
|
||||||
|
func = function(playername, param)
|
||||||
|
if param == nil or param == "" then
|
||||||
|
minetest.chat_send_player(playername, "Provide a number to modify the base heat")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
climate_mod.settings.heat = tonumber(param)
|
||||||
|
minetest.chat_send_player(playername, "Heat changed")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("set_humidity", {
|
||||||
|
params = "<humidity>",
|
||||||
|
description = "Override the weather algorithm's base humidity",
|
||||||
|
privs = { weather = true },
|
||||||
|
func = function(playername, param)
|
||||||
|
if param == nil or param == "" then
|
||||||
|
minetest.chat_send_player(playername, "Provide a number to modify the base humidity")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
climate_mod.settings.humidity = tonumber(param)
|
||||||
|
minetest.chat_send_player(playername, "Humidity changed")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("weather_settings", {
|
||||||
|
description = "Print the active Climate API configuration",
|
||||||
|
privs = { weather = true },
|
||||||
|
func = function(playername)
|
||||||
|
minetest.chat_send_player(playername, "Current Settings\n================")
|
||||||
|
for setting, value in pairs(climate_mod.settings) do
|
||||||
|
minetest.chat_send_player(playername, dump2(value, setting))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
@ -41,4 +41,22 @@ function environment.get_humidity(pos)
|
|||||||
return (base + biome * 0.7 + random_base * 0.3) * random
|
return (base + biome * 0.7 + random_base * 0.3) * random
|
||||||
end
|
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
|
return environment
|
@ -16,12 +16,14 @@ minetest.register_globalstep(function(dtime)
|
|||||||
climate_mod.world.update_status(noise_timer)
|
climate_mod.world.update_status(noise_timer)
|
||||||
end
|
end
|
||||||
|
|
||||||
local effects = climate_mod.trigger.get_active_effects()
|
climate_mod.current_effects = climate_mod.trigger.get_active_effects()
|
||||||
|
|
||||||
for name, effect in pairs(climate_mod.effects) do
|
for name, effect in pairs(climate_mod.effects) do
|
||||||
if climate_mod.cycles[name].timespan < climate_mod.cycles[name].timer + dtime then
|
if climate_mod.cycles[name].timespan < climate_mod.cycles[name].timer + dtime then
|
||||||
climate_mod.cycles[name].timer = 0
|
climate_mod.cycles[name].timer = 0
|
||||||
climate_mod.trigger.call_handlers(name, effects[name])
|
climate_mod.trigger.call_handlers(name, climate_mod.current_effects[name])
|
||||||
|
else
|
||||||
|
climate_mod.cycles[name].timer = climate_mod.cycles[name].timer + dtime
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
@ -43,10 +43,19 @@ local function is_weather_active(player, weather_config, env)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function get_weather_effects(player, weather_config, env)
|
local function get_weather_effects(player, weather_config, env)
|
||||||
|
local config = {}
|
||||||
|
local effects = {}
|
||||||
if type(weather_config.effects) == "function" then
|
if type(weather_config.effects) == "function" then
|
||||||
return weather_config.effects(env)
|
config = weather_config.effects(env)
|
||||||
|
else
|
||||||
|
config = weather_config.effects
|
||||||
end
|
end
|
||||||
return weather_config.effects
|
for effect, value in pairs(config) do
|
||||||
|
if type(climate_mod.effects[effect]) ~= "nil" then
|
||||||
|
effects[effect] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return effects
|
||||||
end
|
end
|
||||||
|
|
||||||
function trigger.get_active_effects()
|
function trigger.get_active_effects()
|
||||||
@ -56,11 +65,16 @@ function trigger.get_active_effects()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local effects = {}
|
local effects = {}
|
||||||
|
climate_mod.current_weather = {}
|
||||||
for wname, wconfig in pairs(climate_mod.weathers) do
|
for wname, wconfig in pairs(climate_mod.weathers) do
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
local pname = player:get_player_name()
|
local pname = player:get_player_name()
|
||||||
local env = environments[pname]
|
local env = environments[pname]
|
||||||
if is_weather_active(player, wconfig, env) then
|
if is_weather_active(player, wconfig, env) then
|
||||||
|
if type(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)
|
local player_effects = get_weather_effects(player, wconfig, env)
|
||||||
for effect, value in pairs(player_effects) do
|
for effect, value in pairs(player_effects) do
|
||||||
if type(effects[effect]) == "nil" then
|
if type(effects[effect]) == "nil" then
|
||||||
|
18
mod.conf
18
mod.conf
@ -4,14 +4,14 @@ author = TestificateMods
|
|||||||
release = 1
|
release = 1
|
||||||
optional_depends = skylayer, player_monoids, playerphysics
|
optional_depends = skylayer, player_monoids, playerphysics
|
||||||
description = """
|
description = """
|
||||||
A powerful engine for weather presets and visual effects.
|
A powerful engine for weather presets and visual effects.
|
||||||
Use the regional climate to set up different effects for different regions.
|
Use the regional climate to set up different effects for different regions.
|
||||||
Control where your effects are activated based on temperature, humidity, wind,
|
Control where your effects are activated based on temperature, humidity, wind,
|
||||||
position, light level or a completely custom activator.
|
position, light level or a completely custom activator.
|
||||||
Climate API provides temperature and humidity values on a block-per-block basis
|
Climate API provides temperature and humidity values on a block-per-block basis
|
||||||
that follow the seasons, day / night cycle and random changes.
|
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.
|
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.
|
Climate API requires additional weather packs in order to function.
|
||||||
Try regional_weather for the best experience.
|
Try regional_weather for the best experience.
|
||||||
"""
|
"""
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.3 MiB |
@ -8,3 +8,4 @@ climate_api_heat_base (Global base temperature) float 0
|
|||||||
climate_api_humidity_base (Global base humidity) float 0
|
climate_api_humidity_base (Global base humidity) float 0
|
||||||
climate_api_time_spread (Regulates how quickly the weather changes) float 1 0.1 10
|
climate_api_time_spread (Regulates how quickly the weather changes) float 1 0.1 10
|
||||||
climate_api_particle_count (Multiplicator for used particles) float 1 0.1 2
|
climate_api_particle_count (Multiplicator for used particles) float 1 0.1 2
|
||||||
|
climate_api_fahrenheit (Show degrees in Fahrenheit instead of Celsius) bool false
|
Loading…
Reference in New Issue
Block a user