commit 2f7d73333a001efb11b838f9c5ab986b01d74a50 Author: runs Date: Sun Jan 24 17:58:59 2021 +0100 first commit diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..560847f --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,18 @@ +unused_args = false +allow_defined_top = true + +globals = { + "minetest", +} + +read_globals = { + string = {fields = {"split"}}, + table = {fields = {"copy", "getn"}}, + + -- Builtin + "vector", "ItemStack", + "dump", "DIR_DELIM", "VoxelArea", "Settings", + + -- MTG + "default", "sfinv", "creative", +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..efb5d1d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,4 @@ +# Licenses + +- Source code: GPLv3. +- Textures: CC BY-SA 4.0 diff --git a/climatez.conf b/climatez.conf new file mode 100644 index 0000000..f8c83ea --- /dev/null +++ b/climatez.conf @@ -0,0 +1,9 @@ +#Chance of the a new area climate to be created +##in seconds +climate_change_ratio = 1200 +#Area of the regional climates (sphere) +climate_radius = 80 +#Average time of the climate +climate_duration = 120 +#Random deviation for the duration +climate_duration_random_ratio = 0.45 diff --git a/engine.lua b/engine.lua new file mode 100644 index 0000000..13215fc --- /dev/null +++ b/engine.lua @@ -0,0 +1,222 @@ +local modpath = ... +local climatez = {} +climatez.wind = {} +climatez.climates = {} +climatez.settings = {} + +--Settings + +local settings = Settings(modpath .. "/climatez.conf") + +climatez.settings.climate_change_ratio = tonumber(settings:get("climate_change_ratio")) +climatez.settings.radius = tonumber(settings:get("climate_radius")) +climatez.settings.climate_duration = tonumber(settings:get("climate_duration")) +climatez.settings.duration_random_ratio = tonumber(settings:get("climate_duration_random_ratio")) + +local check_light = minetest.is_yes(minetest.settings:get_bool('light_roofcheck', true)) + +--Helper Functions + +local function player_inside_climate(player_pos) + --If sphere's centre coordinates is (cx,cy,cz) and its radius is r, + --then point (x,y,z) is in the sphere if (x−cx)2+(y−cy)2+(z−cz)2 math.sqrt((player_pos.x - climate_center.x)^2+ + (player_pos.y - climate_center.y)^2 + + (player_pos.z - climate_center.z)^2 + ) then + return i + end + end + return false +end + +local function has_light(minp, maxp) + local manip = minetest.get_voxel_manip() + local e1, e2 = manip:read_from_map(minp, maxp) + local area = VoxelArea:new{MinEdge=e1, MaxEdge=e2} + local data = manip:get_light_data() + local node_num = 0 + local light = false + + for i in area:iterp(minp, maxp) do + node_num = node_num + 1 + if node_num < 5 then + if data[i] and data[i] == 15 then + light = true + break + end + else + node_num = 0 + end + end + + return light +end + +local function array_remove(tab, idx) + tab[idx] = nil + local new_tab = {} + for _, value in pairs(tab) do + new_tab[ #new_tab+1] = value + end + return new_tab +end + +--DOWNFALLS REGISTRATIONS + +climatez.registered_downfalls = {} + +local function register_downfall(name, def) + local new_def = table.copy(def) + climatez.registered_downfalls[name] = new_def +end + +register_downfall("rain", { + min_pos = {x = -15, y = 10, z = -15}, + max_pos = {x = 15, y = 10, z = 15}, + falling_speed = 10, + amount = 25, + exptime = 1, + size = 1, + texture = "climatez_rain.png", +}) + +register_downfall("snow", { + min_pos = {x = -15, y = 10, z= -15}, + max_pos = {x = 15, y = 10, z = 15}, + falling_speed = 5, + amount = 15, + exptime = 7, + size = 1, + texture= "climatez_snow.png", +}) + +register_downfall("sand", { + min_pos = {x = -20, y = -4, z = -20}, + max_pos = {x = 20, y = 4, z = 20}, + falling_speed = -1, + amount = 40, + exptime = 1, + size = 1, + texture = "climatez_sand.png", +}) + +--WIND STUFF + +local function create_wind() + local wind = { + x = math.random(0,10), + y = 0, + z = math.random(0,10) + } + return wind +end + +function get_player_wind(player) + local player_pos = player:get_pos() + local climate_id = player_inside_climate(player_pos) + if climate_id then + return climatez.climates[climate_id].wind + else + return create_wind() + end +end + +--CLIMATE FUNCTIONS + +local function create_climate(player_pos) + --get some data + local biome_data = minetest.get_biome_data(player_pos) + local biome_heat = biome_data.heat + local biome_humidity = biome_data.humidity + + local downfall + + if biome_heat > 40 and biome_humidity > 50 then + downfall = "rain" + elseif biome_heat > 50 and biome_humidity < 20 then + downfall = "sand" + else + downfall = "snow" + end + + if not downfall then + return + end + + --create wind + local wind = create_wind() + + --create climate + local climate_id = #climatez.climates+1 + climatez.climates[climate_id]= { + center = player_pos, + downfall = downfall, + wind = wind, + } + + --program climate's end + local climate_duration = climatez.settings.climate_duration + local climate_duration_random_ratio = climatez.settings.duration_random_ratio + local random_end_time = (math.random(climate_duration- (climate_duration*climate_duration_random_ratio), + climate_duration+ (climate_duration*climate_duration_random_ratio))) + minetest.after(random_end_time, function() + climatez.climates = array_remove(climatez.climates, climate_id) + end) +end + +local function apply_climate(player, player_pos, climate_id) + + local climate = climatez.climates[climate_id] + local downfall = climatez.registered_downfalls[climate.downfall] + local wind = climatez.climates[climate_id].wind + local wind_pos = vector.multiply(wind, -1) + local minp = vector.add(vector.add(player_pos, downfall.min_pos), wind_pos) + local maxp = vector.add(vector.add(player_pos, downfall.max_pos), wind_pos) + + --Check if in player in interiors or not + if check_light and not has_light(minp, maxp) then + return + end + + local vel = {x = wind.x, y = - downfall.falling_speed, z = wind.z} + local acc = {x = 0, y = 0, z = 0} + local exp = downfall.exptime + + minetest.add_particlespawner({ + amount = downfall.amount, time=0.5, + minpos = minp, maxpos = maxp, + minvel = vel, maxvel = vel, + minacc = acc, maxacc = acc, + minexptime = exp, maxexptime = exp, + minsize = downfall.size, maxsize= downfall.size, + collisiondetection = true, collision_removal = true, + vertical = true, + texture = downfall.texture, playername = player:get_player_name() + }) +end + +--CLIMATE CORE: GLOBALSTEP + +local timer = 0 +minetest.register_globalstep(function(dtime) + timer = timer + dtime; + local player_pos, climate_id + for _, player in ipairs(minetest.get_connected_players()) do + player_pos = player:get_pos() + climate_id = player_inside_climate(player_pos) + if climate_id then + apply_climate(player, player_pos, climate_id) + else + if timer >= 1 then + local chance = math.random(climatez.settings.climate_change_ratio) + if chance == 1 then + create_climate(player_pos) + end + timer = 0 + end + end + end +end) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..1048c4f --- /dev/null +++ b/init.lua @@ -0,0 +1,12 @@ +-- +-- Climatez +-- License:GPLv3 +-- + +local modname = minetest.get_current_modname() +local modpath = minetest.get_modpath(modname) +local mg_name = minetest.get_mapgen_setting("mg_name") + +if mg_name ~= "v6" and mg_name ~= "singlenode" then + assert(loadfile(modpath .. "/engine.lua"))(modpath) +end diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..fde10a9 --- /dev/null +++ b/mod.conf @@ -0,0 +1,2 @@ +name = climatez +description = A weather mod diff --git a/textures/climatez_rain.png b/textures/climatez_rain.png new file mode 100644 index 0000000..6ac252f Binary files /dev/null and b/textures/climatez_rain.png differ diff --git a/textures/climatez_sand.png b/textures/climatez_sand.png new file mode 100644 index 0000000..565ef4b Binary files /dev/null and b/textures/climatez_sand.png differ diff --git a/textures/climatez_snow.png b/textures/climatez_snow.png new file mode 100644 index 0000000..2770d06 Binary files /dev/null and b/textures/climatez_snow.png differ