redesign the api to have player individual weather

This commit is contained in:
theFox6 2020-04-15 17:21:53 +02:00
parent 3d9c292590
commit 63a27f5fcc
Signed by: theFox6
GPG Key ID: C884FE8D3BCE128A
7 changed files with 178 additions and 137 deletions

View File

@ -21,7 +21,6 @@ read_globals = {
globals = { globals = {
"weather", "weather",
"weather_mod"
} }
exclude_files = {"weather/development/"} exclude_files = {"weather/development/"}

View File

@ -1,4 +1,6 @@
weather_mod.registered_downfalls = {} local storage = minetest.get_mod_storage()
weather.registered_downfalls = {}
local function check_modname_prefix(name) local function check_modname_prefix(name)
if name:sub(1,1) == ":" then if name:sub(1,1) == ":" then
@ -66,10 +68,10 @@ local default_damage = {
time = 100 time = 100
} }
function weather_mod.register_downfall(id,def) function weather.register_downfall(id,def)
local name = check_modname_prefix(id) local name = check_modname_prefix(id)
if name == "none" then error("\"none\" means none, thanks") end if name == "none" then error("\"none\" means none, thanks") end
if weather_mod.registered_downfalls[name]~=nil then error(name.." is already registered") end if weather.registered_downfalls[name]~=nil then error(name.." is already registered") end
local ndef = table.copy(def) local ndef = table.copy(def)
--what the downfall looks like --what the downfall looks like
if not ndef.texture then if not ndef.texture then
@ -78,26 +80,26 @@ function weather_mod.register_downfall(id,def)
set_defaults(ndef,default_downfall) set_defaults(ndef,default_downfall)
--when to delete the particles --when to delete the particles
if not ndef.exptime then if not ndef.exptime then
ndef.exptime = ndef.max_pos.y / (math.sqrt(ndef.falling_acceleration) + ndef.falling_speed) ndef.exptime = ndef.max_pos.y / ndef.falling_speed
end end
if ndef.damage_player then if ndef.damage_player then
set_defaults(ndef.damage_player,default_damage) set_defaults(ndef.damage_player,default_damage)
end end
--actually register the downfall --actually register the downfall
weather_mod.registered_downfalls[name]=ndef weather.registered_downfalls[name]=ndef
end end
function weather_mod.disable_downfall(id,disable) function weather.disable_downfall(id,disable)
local state = disable local state = disable
if disable == nil then if disable == nil then
state = true state = true
end end
weather_mod.registered_downfalls[id].disabled = state weather.registered_downfalls[id].disabled = state
end end
--[[
if minetest.get_modpath("lightning") then if minetest.get_modpath("lightning") then
lightning.auto = false lightning.auto = false
--rawset(lightning,"auto",false)
end end
function weather_mod.handle_lightning(current_weather) function weather_mod.handle_lightning(current_weather)
@ -110,10 +112,47 @@ function weather_mod.handle_lightning(current_weather)
minetest.after(time, lightning.strike) minetest.after(time, lightning.strike)
end end
end end
]]
local do_raycasts = minetest.is_yes(minetest.settings:get_bool('raycast_hitcheck')) local do_raycasts = minetest.is_yes(minetest.settings:get_bool('raycast_hitcheck'))
local damage_steps = 0 local damage_steps = 0
local function get_player_meta(player)
local p = player
if type(player) == "string" then
p = minetest.get_player_by_name(player)
end
return p:get_meta()
end
function weather.get_weather(player)
local meta = get_player_meta(player)
return meta:get_string("weather_type")
end
function weather.set_weather(player,type)
local meta = get_player_meta(player)
meta:set_string("weather_type",type)
end
function weather.get_wind()
return {
x = storage:get_float("wind_x"),
y = 0,
z = storage:get_float("wind_z")
}
end
function weather.set_wind(x,z)
if type(x) == "table" then
storage:set_float("wind_x",x.x)
storage:set_float("wind_z",x.z)
else
storage:set_float("wind_x",x)
storage:set_float("wind_z",z)
end
end
local function handle_damage(damage,player, downfall_origin) local function handle_damage(damage,player, downfall_origin)
if not damage then return end if not damage then return end
damage_steps = damage_steps +1 damage_steps = damage_steps +1
@ -143,64 +182,67 @@ local function handle_damage(damage,player, downfall_origin)
end end
end end
local function weather_step() local function weather_step(player,meta)
local current_downfall = weather_mod.registered_downfalls[weather.type] local weather_type = meta:get_string("weather_type")
if current_downfall==nil then return end if weather_type and weather_type ~= "" and weather_type ~= "none" then
for _, player in ipairs(minetest.get_connected_players()) do local current_downfall = weather.registered_downfalls[weather_type]
local ppos = player:getpos() if current_downfall then
local ppos = player:getpos()
if ppos.y > 120 then return end
local wind = weather.get_wind()
local wind_pos = vector.multiply(wind,-1)
if ppos.y > 120 then return end local minp = vector.add(vector.add(ppos, current_downfall.min_pos),wind_pos)
local maxp = vector.add(vector.add(ppos, current_downfall.max_pos),wind_pos)
local wind_pos = vector.multiply(weather.wind,-1)
local vel = {x=wind.x,y=-current_downfall.falling_speed,z=wind.z}
local minp = vector.add(vector.add(ppos, current_downfall.min_pos),wind_pos) local acc = {x=0, y=0, z=0}
local maxp = vector.add(vector.add(ppos, current_downfall.max_pos),wind_pos)
local exp = current_downfall.exptime
local vel = {x=weather.wind.x,y=-current_downfall.falling_speed,z=weather.wind.z}
local acc = {x=0, y=0, z=0} minetest.add_particlespawner({
amount=current_downfall.amount, time=0.5,
local exp = current_downfall.exptime minpos=minp, maxpos=maxp,
minvel=vel, maxvel=vel,
minetest.add_particlespawner({ minacc=acc, maxacc=acc,
amount=current_downfall.amount, time=0.5, minexptime=exp, maxexptime=exp,
minpos=minp, maxpos=maxp, minsize=current_downfall.size, maxsize=current_downfall.size,
minvel=vel, maxvel=vel, collisiondetection=true, collision_removal=true,
minacc=acc, maxacc=acc, vertical=true,
minexptime=exp, maxexptime=exp, texture=current_downfall.texture, playername=player:get_player_name()
minsize=current_downfall.size, maxsize=current_downfall.size, })
collisiondetection=true, collision_removal=true,
vertical=true, local downfall_origin = vector.divide(vector.add(minp,maxp),2)
texture=current_downfall.texture, player=player:get_player_name() handle_damage(current_downfall.damage_player,player,downfall_origin)
}) end
local downfall_origin = vector.divide(vector.add(minp,maxp),2)
handle_damage(current_downfall.damage_player,player,downfall_origin)
end end
end end
minetest.register_globalstep(function() minetest.register_globalstep(function()
if math.random(1, 10000) == 1 then if math.random(1, 50000) == 1 then
weather.type = "none" weather.set_wind(math.random(0,10),math.random(0,10))
if minetest.get_modpath("lightning") then end
lightning.auto = false for _, player in ipairs(minetest.get_connected_players()) do
--rawset(lightning,"auto",false) local meta = get_player_meta(player)
end if math.random(1, 10000) == 1 then
else meta:set_string("weather_type","none")
for id,w in pairs(weather_mod.registered_downfalls) do --[[if minetest.get_modpath("lightning") then
if math.random(1, 50000) == 1 then lightning.auto = false
weather.wind = { end]]
x = math.random(0,10), else
y = 0, for id,w in pairs(weather.registered_downfalls) do
z = math.random(0,10) if math.random(1, 50000) == 1 then
} if (not w.disabled) and vector.length(weather.get_wind()) >= w.min_wind then
if (not w.disabled) and vector.length(weather.wind) >= w.min_wind then meta:set_string("weather_type",id)
weather.type = id --weather_mod.handle_lightning(w)
weather_mod.handle_lightning(w) break
break end
end end
end end
end end
end
weather_step() weather_step(player,meta)
end) end
end)

View File

@ -3,29 +3,35 @@ minetest.register_privilege("weather", {
give_to_singleplayer = false give_to_singleplayer = false
}) })
local function list_types()
local types="none"
for i,_ in pairs(weather.registered_downfalls) do
types=types..", "..i
end
end
-- Set weather -- Set weather
minetest.register_chatcommand("setweather", { minetest.register_chatcommand("setweather", {
params = "<weather>", params = "<weather>",
description = "Set weather to a registered type of downfall\ description = "Set weather to a registered type of downfall\
show all types when no parameters are given", -- full description show all types when no parameters are given", -- full description
privs = {weather = true}, privs = {weather = true},
func = function(name, param) func = function(name, param)
if param == nil or param == "" or param == "?" then if param == nil or param == "" or param == "?" then
local types="none" return false, "registered weather types: "..list_types()
for i,_ in pairs(weather_mod.registered_downfalls) do end
types=types..", "..i local w = weather.registered_downfalls[param]
end if (not w) and param ~= "none" then
minetest.chat_send_player(name, "avalible weather types: "..types) return false, "This type of weather is not registered.\n"..
else "registered types: "..list_types()
if weather_mod.registered_downfalls[param] == nil and not param == "none" then end
minetest.chat_send_player(name, "This type of weather is not registered.\n".. if w.disabled then
"To list all types of weather run the command without parameters.") minetest.chat_send_player(name,param.." is disabled.")
else end
weather.type = param weather.set_weather(name,param)
weather_mod.handle_lightning() --weather_mod.handle_lightning()
end return true
end end
end
}) })
-- Set wind -- Set wind
@ -35,8 +41,7 @@ minetest.register_chatcommand("setwind", {
privs = {weather = true}, privs = {weather = true},
func = function(name, param) func = function(name, param)
if param==nil or param=="" then if param==nil or param=="" then
minetest.chat_send_player(name, "please provide two comma seperated numbers") return false,"please provide two comma seperated numbers"
return
end end
local x,z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)$") local x,z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)$")
x=tonumber(x) x=tonumber(x)
@ -45,9 +50,10 @@ minetest.register_chatcommand("setwind", {
x, z = string.match(param, "^%( *([%d.-]+)[, ] *([%d.-]+) *%)$") x, z = string.match(param, "^%( *([%d.-]+)[, ] *([%d.-]+) *%)$")
end end
if x and z then if x and z then
weather.wind = vector.new(x,0,z) weather.set_wind(x,z)
return true
else else
minetest.chat_send_player(name, param.." are not two comma seperated numbers") return false,param.." are not two comma seperated numbers"
end end
end end
}) })

View File

@ -1,39 +1,11 @@
-- Weather:
-- * rain
-- * snow
-- * wind
assert(minetest.add_particlespawner, "Weather doesn't work with this really old minetest.") assert(minetest.add_particlespawner, "Weather doesn't work with this really old minetest.")
weather_mod={ weather = {
modpath=minetest.get_modpath("weather"), modpath = minetest.get_modpath("weather"),
} }
weather = (function() dofile(weather.modpath.."/api.lua")
local file_name = minetest.get_worldpath() .. "/weather" dofile(weather.modpath.."/rain.lua")
dofile(weather.modpath.."/sand.lua")
minetest.register_on_shutdown(function() dofile(weather.modpath.."/snow.lua")
local file = io.open(file_name, "w") dofile(weather.modpath.."/command.lua")
file:write(minetest.serialize(weather))
file:close()
end)
local file = io.open(file_name, "r")
if file ~= nil then
local readweather = minetest.deserialize(file:read("*a"))
file:close()
if type(readweather)~="table" then
return {type = "none", wind = 0}
end
return readweather
end
return {type = "none", wind = vector.new(0,0,0)}
end) ()
dofile(weather_mod.modpath.."/api.lua")
dofile(weather_mod.modpath.."/rain.lua")
dofile(weather_mod.modpath.."/sand.lua")
dofile(weather_mod.modpath.."/snow.lua")
dofile(weather_mod.modpath.."/command.lua")
weather_mod.handle_lightning()

View File

@ -1,5 +1,5 @@
-- Rain -- Rain
weather_mod.register_downfall("weather:rain",{ weather.register_downfall("weather:rain",{
min_pos = {x=-15, y=7, z=-15}, min_pos = {x=-15, y=7, z=-15},
max_pos = {x= 15, y=7, z= 15}, max_pos = {x= 15, y=7, z= 15},
falling_speed=10, falling_speed=10,
@ -10,7 +10,7 @@ weather_mod.register_downfall("weather:rain",{
enable_lightning=true, enable_lightning=true,
}) })
weather_mod.register_downfall("weather:storm",{ weather.register_downfall("weather:storm",{
min_pos = {x = -15, y = 7, z = -15}, min_pos = {x = -15, y = 7, z = -15},
max_pos = {x = 15, y = 7, z = 15}, max_pos = {x = 15, y = 7, z = 15},
falling_speed = 10, falling_speed = 10,

View File

@ -1,4 +1,4 @@
weather_mod.register_downfall("weather:sandstorm",{ weather.register_downfall("weather:sandstorm",{
min_pos = {x=-20, y=0, z=-20}, min_pos = {x=-20, y=0, z=-20},
max_pos = {x= 20, y=2, z= 20}, max_pos = {x= 20, y=2, z= 20},
falling_speed=-1, falling_speed=-1,

View File

@ -1,5 +1,5 @@
-- Snow -- Snow
weather_mod.register_downfall("weather:snow",{ weather.register_downfall("weather:snow",{
min_pos = {x=-15, y=7, z=-15}, min_pos = {x=-15, y=7, z=-15},
max_pos = {x= 15, y=7, z= 15}, max_pos = {x= 15, y=7, z= 15},
falling_speed=5, falling_speed=5,
@ -9,7 +9,7 @@ weather_mod.register_downfall("weather:snow",{
texture="weather_snow.png", texture="weather_snow.png",
}) })
weather_mod.register_downfall("weather:hail",{ weather.register_downfall("weather:hail",{
min_pos = {x=-15, y=7, z=-15}, min_pos = {x=-15, y=7, z=-15},
max_pos = {x= 15, y=7, z= 15}, max_pos = {x= 15, y=7, z= 15},
falling_speed=25, falling_speed=25,
@ -37,6 +37,25 @@ minetest.register_node("weather:snow_cover", {
drop = {} drop = {}
}) })
local function get_nearest_player(pos,range_distance)
local player, min_distance = nil, range_distance
local position = pos
local all_objects = minetest.get_objects_inside_radius(position, range_distance)
for _, object in pairs(all_objects) do
if object:is_player() then
local player_position = object:getpos()
local distance = vector.distance(position, player_position)
if distance < min_distance then
min_distance = distance
player = object
end
end
end
return player
end
-- Snow cover ABM when snow_covers_abm setting is set to `true` -- Snow cover ABM when snow_covers_abm setting is set to `true`
if minetest.is_yes(minetest.settings:get_bool('snow_covers_abm')) then if minetest.is_yes(minetest.settings:get_bool('snow_covers_abm')) then
minetest.log('action', '[weather] Loaded fast computer ABM (snow covers when weather:snow is set)') minetest.log('action', '[weather] Loaded fast computer ABM (snow covers when weather:snow is set)')
@ -46,16 +65,19 @@ if minetest.is_yes(minetest.settings:get_bool('snow_covers_abm')) then
interval = 10.0, interval = 10.0,
chance = 80, chance = 80,
action = function (pos, node) action = function (pos, node)
if weather.type == "weather:snow" then local player = get_nearest_player(pos,50)
if minetest.registered_nodes[node.name].drawtype == "normal" if not player then return end
or minetest.registered_nodes[node.name].drawtype == "allfaces_optional" then if weather.get_type(player) ~= "weather:snow" then
local np = vector.add(pos, {x=0, y=1, z=0}) return
if minetest.env:get_node_light(np, 0.5) == 15 end
and minetest.env:get_node(np).name == "air" then if minetest.registered_nodes[node.name].drawtype == "normal"
minetest.env:add_node(np, {name="weather:snow_cover"}) or minetest.registered_nodes[node.name].drawtype == "allfaces_optional" then
end local np = vector.add(pos, {x=0, y=1, z=0})
end if minetest.env:get_node_light(np, 0.5) == 15
end and minetest.env:get_node(np).name == "air" then
end minetest.env:add_node(np, {name="weather:snow_cover"})
end
end
end
}) })
end end