358 lines
9.3 KiB
Lua
358 lines
9.3 KiB
Lua
local S = minetest.get_translator(minetest.get_current_modname())
|
|
|
|
-- bell_positions are saved through server restart
|
|
-- bells ring every hour
|
|
-- they ring as many times as a bell ought to
|
|
|
|
local RING_INTERVAL = 3600 --60*60 -- ring each hour
|
|
|
|
local BELL_SAVE_FILE = minetest.get_worldpath().."/bell_positions.data"
|
|
|
|
local bell_positions = {}
|
|
|
|
local ring_big_bell = function(pos)
|
|
minetest.sound_play( "bell_bell",
|
|
{ pos = pos, gain = 1.5, max_hear_distance = 300,})
|
|
end
|
|
-- actually ring the bell
|
|
local ring_bell_once = function()
|
|
for i,v in ipairs( bell_positions ) do
|
|
ring_big_bell(v)
|
|
end
|
|
end
|
|
|
|
local ring_bell_multiple = function(rings)
|
|
for i=1, rings do
|
|
minetest.after( (i-1)*5, ring_bell_once )
|
|
end
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
--- Persistence
|
|
|
|
local save_bell_positions = function()
|
|
|
|
local str = minetest.serialize( ({ bell_data = bell_positions}) )
|
|
|
|
local file, err = io.open( BELL_SAVE_FILE, "wb")
|
|
if (err ~= nil) then
|
|
minetest.log("error", "[bell] Could not save bell data")
|
|
return
|
|
end
|
|
file:write( str )
|
|
file:flush()
|
|
file:close()
|
|
--minetest.chat_send_all("Wrote data to savefile "..tostring( BELL_SAVE_FILE ))
|
|
end
|
|
|
|
local restore_bell_data = function()
|
|
|
|
local bell_position_table
|
|
|
|
local file, err = io.open(BELL_SAVE_FILE, "rb")
|
|
if (err ~= nil) then
|
|
minetest.log("warning", "[bell] Could not open bell data savefile (ignore this message on first start)")
|
|
return
|
|
end
|
|
local str = file:read()
|
|
file:close()
|
|
|
|
local bell_positions_table = minetest.deserialize( str )
|
|
if( bell_positions_table and bell_positions_table.bell_data ) then
|
|
bell_positions = bell_positions_table.bell_data
|
|
minetest.log("action", "[bell] Read positions of bells from savefile.")
|
|
end
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
--- Local time handling
|
|
|
|
local rings_at_dawn = tonumber(minetest.settings:get("bell_tolls_at_dawn")) or 0
|
|
local rings_at_noon = tonumber(minetest.settings:get("bell_tolls_at_noon")) or 0
|
|
local rings_at_dusk = tonumber(minetest.settings:get("bell_tolls_at_dusk")) or 0
|
|
local rings_at_midnight = tonumber(minetest.settings:get("bell_tolls_at_midnight")) or 0
|
|
|
|
local ring_at_dawn = rings_at_dawn > 0
|
|
local ring_at_noon = rings_at_noon > 0
|
|
local ring_at_dusk = rings_at_dusk > 0
|
|
local ring_at_midnight = rings_at_midnight > 0
|
|
local local_time = ring_at_dawn or ring_at_noon or ring_at_dusk or ring_at_midnight
|
|
|
|
local last_timeofday = 0
|
|
local dawn = 0.2 -- day and night in Minetest isn't exactly even
|
|
local noon = 0.5
|
|
local dusk = 0.8
|
|
|
|
if local_time then
|
|
minetest.register_globalstep(function(dtime)
|
|
local timeofday = minetest.get_timeofday()
|
|
if ring_at_dawn and timeofday >= dawn and last_timeofday < dawn then
|
|
ring_bell_multiple(rings_at_dawn)
|
|
last_timeofday = timeofday
|
|
return
|
|
end
|
|
if ring_at_noon and timeofday >= noon and last_timeofday < noon then
|
|
ring_bell_multiple(rings_at_noon)
|
|
last_timeofday = timeofday
|
|
return
|
|
end
|
|
if ring_at_dusk and timeofday >= dusk and last_timeofday < dusk then
|
|
ring_bell_multiple(rings_at_dusk)
|
|
last_timeofday = timeofday
|
|
return
|
|
end
|
|
if ring_at_midnight and timeofday < last_timeofday then
|
|
-- day rolled over, it's midnight
|
|
ring_bell_multiple(rings_at_midnight)
|
|
last_timeofday = timeofday
|
|
return
|
|
end
|
|
last_timeofday = timeofday
|
|
end)
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
--- Global time handling
|
|
|
|
local global_time = minetest.settings:get_bool("bell_tolls_at_server_hours", true)
|
|
|
|
local ring_bell
|
|
ring_bell = function()
|
|
if not global_time then
|
|
return
|
|
end
|
|
|
|
-- figure out if this is the right time to ring
|
|
local sekunde = tonumber( os.date( "%S"))
|
|
local minute = tonumber( os.date( "%M"))
|
|
local stunde = tonumber( os.date( "%I")) -- in 12h-format (a bell that rings 24x at once would not survive long...)
|
|
local delay = RING_INTERVAL
|
|
|
|
--print("[bells]It is now H:"..tostring( stunde ).." M:"..tostring(minute).." S:"..tostring( sekunde ))
|
|
|
|
--local datum = os.date( "Stunde:%l Minute:%M Sekunde:%S")
|
|
--print('[bells] ringing bells at '..tostring( datum ))
|
|
|
|
delay = RING_INTERVAL - sekunde - (minute*60)
|
|
|
|
-- make sure the bell rings the next hour
|
|
minetest.after( delay, ring_bell )
|
|
|
|
-- if no bells are around then don't ring
|
|
if( bell_positions == nil or #bell_positions < 1 ) then
|
|
return
|
|
end
|
|
|
|
if( sekunde > 10 ) then
|
|
-- print("[bells] Too late. Waiting for "..tostring( delay ).." seconds.")
|
|
return
|
|
end
|
|
|
|
-- ring the bell for each hour once
|
|
ring_bell_multiple(stunde)
|
|
end
|
|
|
|
-- first call (after the server has been started)
|
|
minetest.after( 10, ring_bell )
|
|
-- read data about bell positions
|
|
restore_bell_data()
|
|
|
|
---------------------------------------------------------
|
|
--- Node definitions
|
|
|
|
local bell_base = {
|
|
paramtype = "light",
|
|
description = S("Bell"),
|
|
stack_max = 1,
|
|
|
|
on_punch = function (pos,node,puncher)
|
|
ring_big_bell(pos)
|
|
end,
|
|
|
|
on_construct = function(pos)
|
|
-- remember that there is a bell at that position
|
|
table.insert( bell_positions, pos )
|
|
save_bell_positions()
|
|
end,
|
|
|
|
on_destruct = function(pos)
|
|
local found = 0
|
|
-- actually remove the bell from the list
|
|
for i,v in ipairs( bell_positions ) do
|
|
if(v ~= nil and vector.equals(v, pos)) then
|
|
table.remove( bell_positions, i)
|
|
save_bell_positions()
|
|
break
|
|
end
|
|
end
|
|
end,
|
|
|
|
groups = {cracky=2},
|
|
}
|
|
|
|
if minetest.get_modpath("mesecons") then
|
|
bell_base.mesecons = {
|
|
effector = {
|
|
action_on = ring_big_bell,
|
|
}
|
|
}
|
|
end
|
|
|
|
|
|
local ring_small_bell = function(pos)
|
|
minetest.sound_play( "bell_small",
|
|
{ pos = pos, gain = 1.5, max_hear_distance = 60,})
|
|
end
|
|
|
|
|
|
local small_bell_base = {
|
|
description = S("Small bell"),
|
|
paramtype = "light",
|
|
stack_max = 1,
|
|
on_punch = function (pos,node,puncher)
|
|
ring_small_bell(pos)
|
|
end,
|
|
groups = {cracky=2},
|
|
}
|
|
|
|
if minetest.get_modpath("mesecons") then
|
|
small_bell_base.mesecons = {
|
|
effector = {
|
|
action_on = ring_small_bell,
|
|
}
|
|
}
|
|
end
|
|
|
|
----------------------------------------------------
|
|
|
|
if minetest.settings:get_bool("bell_enable_model", true) then
|
|
----------------
|
|
-- Model-type bell
|
|
local bell_def = {
|
|
drawtype = "mesh",
|
|
mesh = "bell_bell.obj",
|
|
tiles = {
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "default_wood.png", backface_culling = true }, --
|
|
},
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
},
|
|
},
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
},
|
|
},
|
|
paramtype2 = "facedir",
|
|
}
|
|
|
|
for k, v in pairs(bell_base) do
|
|
bell_def[k] = v
|
|
end
|
|
|
|
minetest.register_node("bell:bell", bell_def)
|
|
|
|
local small_bell_def =
|
|
{ drawtype = "mesh",
|
|
mesh = "bell_small_bell.obj",
|
|
tiles = {
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "bell_hull.png", backface_culling = true }, --
|
|
{ name = "default_wood.png", backface_culling = true }, --
|
|
},
|
|
collision_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.375, -0.25, -0.375, 0.375, 0.5, 0.375},
|
|
},
|
|
},
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-0.375, -0.25, -0.375, 0.375, 0.5, 0.375},
|
|
},
|
|
},
|
|
paramtype2 = "facedir",
|
|
}
|
|
|
|
for k, v in pairs(small_bell_base) do
|
|
small_bell_def[k] = v
|
|
end
|
|
|
|
minetest.register_node("bell:bell_small", small_bell_def)
|
|
|
|
else
|
|
--------------------
|
|
-- Plantlike-type bell
|
|
local bell_def = {
|
|
tiles = {"bell_bell.png"},
|
|
inventory_image = 'bell_bell.png',
|
|
wield_image = 'bell_bell.png',
|
|
drawtype = "plantlike",
|
|
}
|
|
for k, v in pairs(bell_base) do
|
|
bell_def[k] = v
|
|
end
|
|
|
|
minetest.register_node("bell:bell", bell_def)
|
|
|
|
local small_bell_def = {
|
|
tiles = {"bell_bell.png"},
|
|
inventory_image = 'bell_bell.png',
|
|
wield_image = 'bell_bell.png',
|
|
drawtype = "plantlike",
|
|
}
|
|
for k, v in pairs(small_bell_base) do
|
|
small_bell_def[k] = v
|
|
end
|
|
|
|
minetest.register_node("bell:bell_small", small_bell_def)
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
--- Recipes
|
|
|
|
if minetest.get_modpath("default") then
|
|
minetest.register_craft({
|
|
output = "bell:bell_small",
|
|
recipe = {
|
|
{"", "default:goldblock", "" },
|
|
{"default:goldblock", "default:goldblock", "default:goldblock"},
|
|
{"default:goldblock", "", "default:goldblock"},
|
|
},
|
|
})
|
|
minetest.register_craft({
|
|
output = "bell:bell",
|
|
recipe = {
|
|
{"default:goldblock", "default:goldblock", "default:goldblock"},
|
|
{"default:goldblock", "default:goldblock", "default:goldblock"},
|
|
{"default:goldblock", "", "default:goldblock"},
|
|
},
|
|
})
|
|
end
|
|
|
|
if minetest.get_modpath("mcl_core") then
|
|
minetest.register_craft({
|
|
output = "bell:bell_small",
|
|
recipe = {
|
|
{"", "mcl_core:goldblock", "" },
|
|
{"mcl_core:goldblock", "mcl_core:goldblock", "mcl_core:goldblock"},
|
|
{"mcl_core:goldblock", "", "mcl_core:goldblock"},
|
|
},
|
|
})
|
|
minetest.register_craft({
|
|
output = "bell:bell",
|
|
recipe = {
|
|
{"mcl_core:goldblock", "mcl_core:goldblock", "mcl_core:goldblock"},
|
|
{"mcl_core:goldblock", "mcl_core:goldblock", "mcl_core:goldblock"},
|
|
{"mcl_core:goldblock", "", "mcl_core:goldblock"},
|
|
},
|
|
})
|
|
end |