diff --git a/README.md b/README.md new file mode 100644 index 0000000..0eb3b56 --- /dev/null +++ b/README.md @@ -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 \ No newline at end of file diff --git a/TODO.md b/TODO.md index 383fa10..d8f494e 100644 --- a/TODO.md +++ b/TODO.md @@ -27,13 +27,16 @@ - Make switches between effects more smooth - Adjust size of particle boxes based on player speed - 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 - 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 nycle adjusted to season + - day/night cycle adjusted to season - special events like a bloodmoon -> increased mob spawns - Fantasy weather effects - pretty skyboxes diff --git a/ca_effects/clouds.lua b/ca_effects/clouds.lua index 2f8487d..32cb997 100644 --- a/ca_effects/clouds.lua +++ b/ca_effects/clouds.lua @@ -24,12 +24,6 @@ end local function handle_effect(player_data) for playername, data in pairs(player_data) do 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 = {} for weather, value in pairs(data) do clouds.size = accumulate(clouds.size, data.size, function(a, b) return a * b end) diff --git a/init.lua b/init.lua index 9190b0f..53ae2e9 100644 --- a/init.lua +++ b/init.lua @@ -7,11 +7,15 @@ local modname = minetest.get_current_modname() local modpath = minetest.get_modpath(modname) 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 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 -- load settings from config file @@ -21,14 +25,19 @@ climate_mod.settings = { sound = getBoolSetting("sound", true), wind = getBoolSetting("wind", true), seasons = getBoolSetting("seasons", true), + fahrenheit = getBoolSetting("fahrenheit", false), heat = getNumericSetting("heat_base", 0), humidity = getNumericSetting("humidity_base", 0), time_spread = getNumericSetting("time_spread", 1), particle_count = getNumericSetting("particle_count", 1) } +-- initiate empty registers climate_mod.current_weather = {} climate_mod.current_effects = {} +climate_mod.weathers = {} +climate_mod.effects = {} +climate_mod.cycles = {} -- import core API 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.trigger = dofile(modpath .. "/lib/trigger.lua") dofile(modpath.."/lib/main.lua") +dofile(modpath.."/lib/commands.lua") -- import predefined environment effects dofile(modpath .. "/ca_effects/particles.lua") diff --git a/lib/api.lua b/lib/api.lua index 5e9dcaa..abdc7f5 100644 --- a/lib/api.lua +++ b/lib/api.lua @@ -5,10 +5,6 @@ api.DEFAULT_CYCLE = 0.1 -- for most effect types api.MEDIUM_CYCKE = 2.0 -- for ressource intensive tasks 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) -- TODO: check and sanitize climate_mod.weathers[name] = { diff --git a/lib/commands.lua b/lib/commands.lua new file mode 100644 index 0000000..5ef3d7e --- /dev/null +++ b/lib/commands.lua @@ -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 = "", + 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 = "", + 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 +}) \ No newline at end of file diff --git a/lib/environment.lua b/lib/environment.lua index 123527f..e060e68 100644 --- a/lib/environment.lua +++ b/lib/environment.lua @@ -41,4 +41,22 @@ function environment.get_humidity(pos) return (base + biome * 0.7 + random_base * 0.3) * random 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 \ No newline at end of file diff --git a/lib/main.lua b/lib/main.lua index 3f88b65..71f2773 100644 --- a/lib/main.lua +++ b/lib/main.lua @@ -16,12 +16,14 @@ minetest.register_globalstep(function(dtime) climate_mod.world.update_status(noise_timer) 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 if climate_mod.cycles[name].timespan < climate_mod.cycles[name].timer + dtime then 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) \ No newline at end of file diff --git a/lib/trigger.lua b/lib/trigger.lua index 7ebec4b..b449fcc 100644 --- a/lib/trigger.lua +++ b/lib/trigger.lua @@ -43,10 +43,19 @@ local function is_weather_active(player, weather_config, env) end local function get_weather_effects(player, weather_config, env) + local config = {} + local effects = {} if type(weather_config.effects) == "function" then - return weather_config.effects(env) + config = weather_config.effects(env) + else + config = weather_config.effects 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 function trigger.get_active_effects() @@ -56,11 +65,16 @@ function trigger.get_active_effects() 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 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) for effect, value in pairs(player_effects) do if type(effects[effect]) == "nil" then diff --git a/mod.conf b/mod.conf index 2f158d2..8a28d6b 100644 --- a/mod.conf +++ b/mod.conf @@ -4,14 +4,14 @@ author = TestificateMods release = 1 optional_depends = skylayer, player_monoids, playerphysics 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. +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. +Climate API requires additional weather packs in order to function. +Try regional_weather for the best experience. """ \ No newline at end of file diff --git a/screenshot.png b/screenshot.png index 84704ea..dc9a6cd 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/settingtypes.txt b/settingtypes.txt index dfaed0b..7806ff6 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -7,4 +7,5 @@ climate_api_seasons (Change global temperature based on an annual cycle) bool tr climate_api_heat_base (Global base temperature) 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_particle_count (Multiplicator for used particles) float 1 0.1 2 \ No newline at end of file +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 \ No newline at end of file