add weather affect area support
parent
a234e89801
commit
a82cda5849
62
README.md
62
README.md
|
@ -1,34 +1,44 @@
|
|||
# Happy Weather API
|
||||
a minetest mod-api for creating own weather
|
||||
Happy Weather API
|
||||
===================
|
||||
Minetest mod-api to help organize weathers.
|
||||
|
||||
```
|
||||
-- Main weather object template
|
||||
local weather_obj = {
|
||||
-- Weather code used to identify weather
|
||||
code = "weather code",
|
||||
Overview
|
||||
------------
|
||||
All weathers parameters and functions should be defined under single object. For reference lets call it `weather_obj`.
|
||||
|
||||
-- Managed by API. Returns true if weather active, false otherwise
|
||||
active = "false",
|
||||
Weather object fields
|
||||
-------
|
||||
Weather code is mandatory property.
|
||||
|
||||
-- Will be called to check if wheater should be activated
|
||||
about_to_start = "function(dtime)",
|
||||
property name | description
|
||||
------------------ | ---------------------------------
|
||||
code | used to identify weather
|
||||
active | weather state flag managed by API
|
||||
affected_players | table of players affected by weather managed by API
|
||||
|
||||
-- Will be called to check if wheater should be deactivated
|
||||
about_to_end = "function(dtime)",
|
||||
Weather object callback methods
|
||||
-------
|
||||
Callback methods which will be invoked by API. It's recommended to implement all bellow callback methods.
|
||||
|
||||
-- Will be called on weather start
|
||||
setup = "function(player)",
|
||||
function name | arguments | return type | description
|
||||
------------- | --------------- | ----------- | -----------
|
||||
is_starting | dtime, position | boolean | should return true if weather is ready to start, false otherwise.
|
||||
is_ending | dtime | boolean | should return true if weather is ready to end, false otherwise.
|
||||
add_player | player | void | should apply effect for player (change sky, initialize sounds and etc).
|
||||
remove_player | player | void | should remove weather from player
|
||||
in_area | position | boolean | should return true if position is in weather area, false otherwise.
|
||||
render | dtime, player | void | should apply visual, sound or anything else needed to represent weather.
|
||||
|
||||
-- Will be called on game step
|
||||
update = "function(dtime, player)",
|
||||
These methods are not part of weather API lifecycle and expected to be invoked manually (e.g. weather commands, other weather related mods).
|
||||
function name | arguments | return type | description
|
||||
------------- | --------- | ----------- | -----------
|
||||
start | position | void | should start weather at given position
|
||||
stop | < none > | void | should end weather
|
||||
|
||||
-- Will be called on weather end (after condition_check returns false)
|
||||
clear_up = "function(player)",
|
||||
Weather API methods
|
||||
-------
|
||||
function name | arguments | return type | description
|
||||
----------------- | ------------- | ----------- | -----------
|
||||
register_weather | weather_obj | void | will register weather
|
||||
is_weather_active | weather_code | boolean | will return true if weather is active, false otherwise
|
||||
|
||||
-- Will be called with intention to start weather
|
||||
manual_trigger_start = "function()",
|
||||
|
||||
-- Will be called with intention to end weather
|
||||
manual_trigger_end = "function()"
|
||||
}
|
||||
```
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
---------------------------
|
||||
-- Happy Weather API
|
||||
|
||||
-- License: MIT
|
||||
-- Credits: xeranas
|
||||
---------------------------
|
||||
|
||||
-- Main object which will be used in Weather API lifecycle
|
||||
happy_weather = {}
|
||||
|
||||
-- Local variables which helps organize active and deactive weahers
|
||||
local registered_weathers = {}
|
||||
local active_weathers = {}
|
||||
|
||||
---------------------------
|
||||
-- Weather API functions --
|
||||
---------------------------
|
||||
|
||||
-- Adds weather to register_weathers table
|
||||
happy_weather.register_weather = function(weather_obj)
|
||||
table.insert(registered_weathers, weather_obj)
|
||||
end
|
||||
|
||||
-- Returns true if weather is active right now, false otherwise
|
||||
happy_weather.is_weather_active = function(weather_code)
|
||||
if #active_weathers == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
for k, weather_ in ipairs(active_weathers) do
|
||||
if weather_.code == weather_code then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Requests weaher to start
|
||||
happy_weather.request_to_start = function(weather_code, position)
|
||||
if #registered_weathers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
for k, weather_ in ipairs(registered_weathers) do
|
||||
if weather_.code == weather_code and weather_.start ~= nil then
|
||||
weather_.start(position)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Requests weaher to end
|
||||
happy_weather.request_to_end = function(weather_code)
|
||||
if #active_weathers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
for k, weather_ in ipairs(active_weathers) do
|
||||
if weather_.code == weather_code and weather_.stop ~= nil then
|
||||
weather_.stop()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------
|
||||
-- Local helper / utility methods --
|
||||
------------------------------------
|
||||
|
||||
-- Adds weather to active_weathers table
|
||||
local add_active_weather = function(weather_obj)
|
||||
table.insert(active_weathers, weather_obj)
|
||||
end
|
||||
|
||||
-- Remove weather from active_weathers table
|
||||
local remove_active_weather = function(weather_code)
|
||||
if #active_weathers == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
for k, weather_ in ipairs(active_weathers) do
|
||||
if weather_.code == weather_code then
|
||||
table.remove(active_weathers, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- adds player to affected_players table
|
||||
local add_player = function(affected_players, player)
|
||||
table.insert(affected_players, player)
|
||||
end
|
||||
|
||||
-- remove player from affected_players table
|
||||
local remove_player = function(affected_players, player_name)
|
||||
if #affected_players == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
for k, player_ in ipairs(affected_players) do
|
||||
if player_:get_player_name() == player_name then
|
||||
table.remove(affected_players, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local is_player_affected = function(affected_players, player_name)
|
||||
if #affected_players == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
for k, player_ in ipairs(affected_players) do
|
||||
if player_:get_player_name() == player_name then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Weather object callback wrappers to avoid issues from undefined methods --
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-- Weather is_starting method nil-safe wrapper
|
||||
local weather_is_starting = function(weather_obj, dtime, position)
|
||||
if weather_obj.is_starting == nil then
|
||||
return false
|
||||
end
|
||||
return weather_obj.is_starting(dtime, position)
|
||||
end
|
||||
|
||||
-- Weather is_starting method nil-safe wrapper
|
||||
local weather_is_ending = function(weather_obj, dtime)
|
||||
if weather_obj.is_ending == nil then
|
||||
return false
|
||||
end
|
||||
return weather_obj.is_ending(dtime)
|
||||
end
|
||||
|
||||
-- Weather add_player method nil-safe wrapper
|
||||
local weather_add_player = function(weather_obj, player)
|
||||
if weather_obj.add_player == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.add_player(player)
|
||||
end
|
||||
|
||||
-- Weather remove_player method nil-safe wrapper
|
||||
local weather_remove_player = function(weather_obj, player)
|
||||
if weather_obj.remove_player == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.remove_player(player)
|
||||
end
|
||||
|
||||
-- Weather remove_player method nil-safe wrapper
|
||||
local weather_in_area = function(weather_obj, position)
|
||||
if weather_obj.in_area == nil then
|
||||
return true
|
||||
end
|
||||
return weather_obj.in_area(position)
|
||||
end
|
||||
|
||||
-- Weather render method nil-safe wrapper
|
||||
local weather_render = function(weather_obj, dtime, player)
|
||||
if weather_obj.render == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.render(dtime, player)
|
||||
end
|
||||
|
||||
-- Weather start method nil-safe wrapper
|
||||
local weather_start = function(weather_obj, player)
|
||||
if weather_obj.start == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.start(player)
|
||||
end
|
||||
|
||||
-- Weather stop method nil-safe wrapper
|
||||
local weather_stop = function(weather_obj, player)
|
||||
if weather_obj.stop == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.stop(player)
|
||||
end
|
||||
|
||||
-- Perform clean-up callbacks calls sets flags upon weaher end
|
||||
local prepare_ending = function(weather_obj, player)
|
||||
weather_obj.active = false
|
||||
remove_active_weather(weather_obj.code)
|
||||
weather_remove_player(weather_obj, player)
|
||||
remove_player(weather_obj.affected_players, player:get_player_name())
|
||||
end
|
||||
|
||||
-- Perform weather setup for certain player
|
||||
local prepare_starting = function(weather_obj, player)
|
||||
weather_obj.active = true
|
||||
weather_obj.affected_players = {}
|
||||
add_active_weather(weather_obj)
|
||||
end
|
||||
|
||||
-- While still active weather can or can not affect players based on area they are
|
||||
local render_if_in_area = function(weather_obj, dtime, player)
|
||||
if is_player_affected(weather_obj.affected_players, player:get_player_name()) then
|
||||
if weather_in_area(weather_obj, player:getpos()) then
|
||||
weather_render(weather_obj, dtime, player)
|
||||
else
|
||||
weather_remove_player(weather_obj, player)
|
||||
remove_player(weather_obj.affected_players, player:get_player_name())
|
||||
end
|
||||
else
|
||||
if weather_in_area(weather_obj, player:getpos()) then
|
||||
add_player(weather_obj.affected_players, player)
|
||||
weather_add_player(weather_obj, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------
|
||||
-- Global step function --
|
||||
--------------------------
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
||||
if #registered_weathers == 0 then
|
||||
-- no registered weathers, do nothing.
|
||||
return
|
||||
end
|
||||
|
||||
if #minetest.get_connected_players() == 0 then
|
||||
-- no actual players, do nothing.
|
||||
return
|
||||
end
|
||||
|
||||
-- Loop through registered weathers
|
||||
for i, weather_ in ipairs(registered_weathers) do
|
||||
|
||||
-- Loop through connected players
|
||||
for ii, player in ipairs(minetest.get_connected_players()) do
|
||||
|
||||
-- Weaher is active checking if it about to end
|
||||
if weather_.active then
|
||||
if weather_is_ending(weather_, dtime) then
|
||||
prepare_ending(weather_, player)
|
||||
|
||||
-- Weather still active updating it
|
||||
else
|
||||
render_if_in_area(weather_, dtime, player)
|
||||
end
|
||||
|
||||
-- Weaher is not active checking if it about to start
|
||||
else
|
||||
if weather_.is_starting(dtime, player:getpos()) then
|
||||
prepare_starting(weather_, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
10
commands.lua
10
commands.lua
|
@ -1,10 +1,10 @@
|
|||
--
|
||||
------------------------------------
|
||||
-- Happy Weather API Chat Commands
|
||||
|
||||
-- License: MIT
|
||||
|
||||
-- Credits:
|
||||
-- * xeranas
|
||||
-- Credits: xeranas
|
||||
------------------------------------
|
||||
|
||||
minetest.register_privilege("weather_manager", {
|
||||
description = "Gives ability to control weather",
|
||||
|
@ -18,7 +18,7 @@ minetest.register_chatcommand("start_weather", {
|
|||
func = function(name, param)
|
||||
if param ~= nil then
|
||||
happy_weather.request_to_start(param)
|
||||
minetest.log("action", name .. " requested to start weather '" .. param .. "' from chat command.")
|
||||
minetest.log("action", name .. " requested weather '" .. param .. "' from chat command")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
@ -30,7 +30,7 @@ minetest.register_chatcommand("stop_weather", {
|
|||
func = function(name, param)
|
||||
if param ~= nil then
|
||||
happy_weather.request_to_end(param)
|
||||
minetest.log("action", name .. " requested to stop weather '" .. param .. "' from chat command.")
|
||||
minetest.log("action", name .. " requested weather '" .. param .. "' ending from chat command")
|
||||
end
|
||||
end
|
||||
})
|
|
@ -1,127 +0,0 @@
|
|||
--
|
||||
-- Happy Weather API
|
||||
|
||||
-- License: MIT
|
||||
|
||||
-- Credits:
|
||||
-- * xeranas
|
||||
|
||||
|
||||
happy_weather = {}
|
||||
|
||||
local registered_weathers = {}
|
||||
local active_weathers = {}
|
||||
|
||||
|
||||
happy_weather.register_weather = function(weather_obj)
|
||||
table.insert(registered_weathers, weather_obj)
|
||||
end
|
||||
|
||||
happy_weather.is_weather_active = function(weather_cd)
|
||||
for k, weather_ in ipairs(active_weathers) do
|
||||
if weather_.code == weather_cd then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local add_active_weather = function(weather_obj)
|
||||
table.insert(active_weathers, weather_obj)
|
||||
end
|
||||
|
||||
local remove_active_weather = function(weather_cd)
|
||||
for k, weather_ in ipairs(active_weathers) do
|
||||
if weather_.code == weather_cd then
|
||||
table.remove(active_weathers, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Ask to start weather. Expected to be trigger from weather implelentation side.
|
||||
happy_weather.request_to_start = function(weather_cd)
|
||||
for k, weather_ in ipairs(registered_weathers) do
|
||||
if weather_.code == weather_cd and weather_.manual_trigger_start ~= nil then
|
||||
weather_.manual_trigger_start()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Ask to end weather. Expected to be trigger from weather implelentation side.
|
||||
happy_weather.request_to_end = function(weather_cd)
|
||||
for k, weather_ in ipairs(registered_weathers) do
|
||||
if weather_.code == weather_cd and weather_.manual_trigger_end ~= nil then
|
||||
weather_.manual_trigger_end()
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Weather setup method wrapper (nil-safe)
|
||||
local weather_setup = function(weather_obj, player)
|
||||
if weather_obj.setup == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.setup(player)
|
||||
end
|
||||
|
||||
-- Weather clear up method wrapper (nil-safe)
|
||||
local weather_clear_up = function(weather_obj, player)
|
||||
if weather_obj.clear_up == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.clear_up(player)
|
||||
end
|
||||
|
||||
-- Weather update method wrapper (nil-safe)
|
||||
local weather_update = function(weather_obj, dtime, player)
|
||||
if weather_obj.update == nil then
|
||||
return
|
||||
end
|
||||
weather_obj.update(dtime, player)
|
||||
end
|
||||
|
||||
-- Global step function
|
||||
-- loop through registered weathers and check which weather is about to start or end
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
||||
if #registered_weathers == 0 then
|
||||
-- no registered weathers, do nothing.
|
||||
return
|
||||
end
|
||||
|
||||
if #minetest.get_connected_players() == 0 then
|
||||
-- no actual players, do nothing.
|
||||
return
|
||||
end
|
||||
|
||||
-- Loop through registered weathers
|
||||
for i, weather_ in ipairs(registered_weathers) do
|
||||
-- Loop through connected players (weathers are attached to players)
|
||||
for ii, player in ipairs(minetest.get_connected_players()) do
|
||||
|
||||
-- Weaher is active checking if it about to end
|
||||
if (weather_.active) then
|
||||
if (weather_.about_to_end(dtime)) then
|
||||
weather_clear_up(weather_, player)
|
||||
weather_.active = false
|
||||
remove_active_weather(weather_.code)
|
||||
|
||||
-- Weather still active updating it
|
||||
else
|
||||
weather_update(weather_, dtime, player)
|
||||
end
|
||||
|
||||
-- Weaher is not active checking if it about to start
|
||||
else
|
||||
if (weather_.about_to_start(dtime)) then
|
||||
weather_setup(weather_, player)
|
||||
weather_.active = true
|
||||
add_active_weather(weather_)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
10
init.lua
10
init.lua
|
@ -1,11 +1,11 @@
|
|||
--
|
||||
-- Happy Weather API Initialization
|
||||
--------------------------------------
|
||||
-- Happy Weather API: initialization
|
||||
|
||||
-- License: MIT
|
||||
|
||||
-- Credits:
|
||||
-- * xeranas
|
||||
-- Credits: xeranas
|
||||
--------------------------------------
|
||||
|
||||
local modpath = minetest.get_modpath("happy_weather_api");
|
||||
dofile(modpath.."/happy_weather_api.lua")
|
||||
dofile(modpath.."/api.lua")
|
||||
dofile(modpath.."/commands.lua")
|
Loading…
Reference in New Issue