Rename beds mod to mcl_beds

This commit is contained in:
Wuzzy 2017-05-07 20:21:37 +02:00
parent 4c71611c3d
commit d76ab30892
19 changed files with 102 additions and 83 deletions

View file

@ -0,0 +1,26 @@
Minetest Game mod: beds
=======================
See license.txt for license information.
Authors of source code
----------------------
Originally by BlockMen (MIT)
Various Minetest developers and contributors (MIT)
Authors of media (textures)
---------------------------
BlockMen (CC BY-SA 3.0)
This mod adds a bed to Minetest which allows to skip the night.
To sleep, rightclick the bed. If playing in singleplayer mode the night gets skipped
immediately. If playing multiplayer you get shown how many other players are in bed too,
if all players are sleeping the night gets skipped. The night skip can be forced if more
than 50% of the players are lying in bed and use this option.
Another feature is a controlled respawning. If you have slept in bed (not just lying in
it) your respawn point is set to the beds location and you will respawn there after
death.
You can disable the respawn at beds by setting "enable_bed_respawn = false" in
minetest.conf.
You can disable the night skip feature by setting "enable_bed_night_skip = false" in
minetest.conf or by using the /set command in-game.

190
mods/ITEMS/mcl_beds/api.lua Normal file
View file

@ -0,0 +1,190 @@
local reverse = true
local function destruct_bed(pos, n)
local node = minetest.get_node(pos)
local other
if n == 2 then
local dir = minetest.facedir_to_dir(node.param2)
other = vector.subtract(pos, dir)
elseif n == 1 then
local dir = minetest.facedir_to_dir(node.param2)
other = vector.add(pos, dir)
end
if reverse then
reverse = not reverse
minetest.remove_node(other)
minetest.check_for_falling(other)
else
reverse = not reverse
end
end
local beddesc = "Beds allow you to sleep at night and waste some time. Survival in this world does not demand sleep, but sleeping might have some other uses. "
local beduse = "Right-click on the bed to try to sleep in it. This only works when the sun sets or at night."
if minetest.setting_getbool("enable_bed_respawn") == false then
beddesc = beddesc .. "In local folklore, legends are told of other worlds where setting the start point for your next would be possible. But this world is not one of them. "
else
beddesc = beddesc .. "By sleeping in a bed, you set the starting point for your next life. "
end
if minetest.setting_getbool("enable_bed_night_skip") == false then
beddesc = beddesc .. "In this strange world, the time will not pass faster for you when you sleep."
else
beddesc = beddesc .. "Going into bed seems to make time pass faster: The night will be skipped when you go sleep and you're alone in this world. If you're not alone, the night is skipped when all players in this world went to sleep."
end
function mcl_beds.register_bed(name, def)
minetest.register_node(name .. "_bottom", {
description = def.description,
_doc_items_longdesc = def._doc_items_longdesc or beddesc,
_doc_items_usagehelp = def._doc_items_usagehelp or beduse,
inventory_image = def.inventory_image,
wield_image = def.wield_image,
drawtype = "nodebox",
tiles = def.tiles.bottom,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
is_ground_content = false,
stack_max = 1,
groups = {handy=1, flammable = 3, bed = 1, dig_by_piston=1, fall_damage_add_percent=-50},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or mcl_sounds.node_sound_wood_defaults(),
node_box = {
type = "fixed",
fixed = def.nodebox.bottom,
},
selection_box = {
type = "fixed",
fixed = def.selectionbox.bottom,
},
on_place = function(itemstack, placer, pointed_thing)
local under = pointed_thing.under
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
local pos
if minetest.registered_items[minetest.get_node(under).name].buildable_to then
pos = under
else
pos = pointed_thing.above
end
if minetest.is_protected(pos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(pos, placer:get_player_name())
return itemstack
end
local node_def = minetest.registered_nodes[minetest.get_node(pos).name]
if not node_def or not node_def.buildable_to then
return itemstack
end
local dir = minetest.dir_to_facedir(placer:get_look_dir())
local botpos = vector.add(pos, minetest.facedir_to_dir(dir))
if minetest.is_protected(botpos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(botpos, placer:get_player_name())
return itemstack
end
local botdef = minetest.registered_nodes[minetest.get_node(botpos).name]
if not botdef or not botdef.buildable_to then
return itemstack
end
minetest.set_node(pos, {name = name .. "_bottom", param2 = dir})
minetest.set_node(botpos, {name = name .. "_top", param2 = dir})
if not minetest.setting_getbool("creative_mode") then
itemstack:take_item()
end
return itemstack
end,
on_destruct = function(pos)
destruct_bed(pos, 1)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
mcl_beds.on_rightclick(pos, clicker)
return itemstack
end,
on_rotate = function(pos, node, user, mode, new_param2)
local dir = minetest.facedir_to_dir(node.param2)
local p = vector.add(pos, dir)
local node2 = minetest.get_node_or_nil(p)
if not node2 or not minetest.get_item_group(node2.name, "bed") == 2 or
not node.param2 == node2.param2 then
return false
end
if minetest.is_protected(p, user:get_player_name()) then
minetest.record_protection_violation(p, user:get_player_name())
return false
end
if mode ~= screwdriver.ROTATE_FACE then
return false
end
local newp = vector.add(pos, minetest.facedir_to_dir(new_param2))
local node3 = minetest.get_node_or_nil(newp)
local node_def = node3 and minetest.registered_nodes[node3.name]
if not node_def or not node_def.buildable_to then
return false
end
if minetest.is_protected(newp, user:get_player_name()) then
minetest.record_protection_violation(newp, user:get_player_name())
return false
end
node.param2 = new_param2
-- do not remove_node here - it will trigger destroy_bed()
minetest.set_node(p, {name = "air"})
minetest.set_node(pos, node)
minetest.set_node(newp, {name = name .. "_top", param2 = new_param2})
return true
end,
})
minetest.register_node(name .. "_top", {
drawtype = "nodebox",
tiles = def.tiles.top,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
is_ground_content = false,
groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, fall_damage_add_percent=-50},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
sounds = def.sounds or mcl_sounds.node_sound_wood_defaults(),
drop = name .. "_bottom",
node_box = {
type = "fixed",
fixed = def.nodebox.top,
},
selection_box = {
type = "fixed",
fixed = def.selectionbox.top,
},
on_destruct = function(pos)
destruct_bed(pos, 2)
end,
})
minetest.register_alias(name, name .. "_bottom")
minetest.register_craft({
output = name,
recipe = def.recipe
})
end

View file

@ -0,0 +1,50 @@
-- 3D bed
local nodebox = {
bottom = {
{-0.5, -5/16, -0.5, 0.5, 0.06, 0.5},
{-0.5, -0.5, -0.5, -5/16, -5/16, -5/16},
{0.5, -0.5, -0.5, 5/16, -5/16, -5/16},
},
top = {
{-0.5, -5/16, -0.5, 0.5, 0.06, 0.5},
{-0.5, -0.5, 0.5, -5/16, -5/16, 5/16},
{0.5, -0.5, 0.5, 5/16, -5/16, 5/16},
},
}
mcl_beds.register_bed("mcl_beds:bed_red", {
description = "Bed",
inventory_image = "mcl_beds_bed_red.png",
wield_image = "mcl_beds_bed_red.png",
tiles = {
bottom = {
"mcl_beds_bed_top_bottom_red.png",
"mcl_beds_bed_bottom_bottom.png",
"mcl_beds_bed_side_bottom_r_red.png",
"mcl_beds_bed_side_bottom_r_red.png^[transformfx",
"mcl_beds_bed_side_top_red.png",
"mcl_beds_bed_side_bottom_red.png"
},
top = {
"mcl_beds_bed_top_top_red.png",
"mcl_beds_bed_bottom_top.png",
"mcl_beds_bed_side_top_r_red.png",
"mcl_beds_bed_side_top_r_red.png^[transformfx",
"mcl_beds_bed_side_top_red.png",
"mcl_beds_bed_side_bottom_red.png"
}
},
nodebox = nodebox,
selectionbox = {
bottom = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
top = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
},
recipe = {
{"group:wool", "group:wool", "group:wool"},
{"group:wood", "group:wood", "group:wood"}
},
})
minetest.register_alias("beds:bed_bottom", "mcl_beds:bed_red_bottom")
minetest.register_alias("beds:bed_top", "mcl_beds:bed_red_top")

View file

@ -0,0 +1,3 @@
mcl_core
mcl_sounds
mcl_wool

View file

@ -0,0 +1,221 @@
local pi = math.pi
local player_in_bed = 0
local is_sp = minetest.is_singleplayer()
local enable_respawn = minetest.setting_getbool("enable_bed_respawn")
if enable_respawn == nil then
enable_respawn = true
end
-- Helper functions
local function get_look_yaw(pos)
local n = minetest.get_node(pos)
if n.param2 == 1 then
return pi / 2, n.param2
elseif n.param2 == 3 then
return -pi / 2, n.param2
elseif n.param2 == 0 then
return pi, n.param2
else
return 0, n.param2
end
end
local function is_night_skip_enabled()
local enable_night_skip = minetest.setting_getbool("enable_bed_night_skip")
if enable_night_skip == nil then
enable_night_skip = true
end
return enable_night_skip
end
local function check_in_beds(players)
local in_bed = mcl_beds.player
if not players then
players = minetest.get_connected_players()
end
for n, player in ipairs(players) do
local name = player:get_player_name()
if not in_bed[name] then
return false
end
end
return #players > 0
end
local function lay_down(player, pos, bed_pos, state, skip)
local name = player:get_player_name()
local hud_flags = player:hud_get_flags()
if not player or not name then
return
end
-- stand up
if state ~= nil and not state then
local p = mcl_beds.pos[name] or nil
if mcl_beds.player[name] ~= nil then
mcl_beds.player[name] = nil
player_in_bed = player_in_bed - 1
end
-- skip here to prevent sending player specific changes (used for leaving players)
if skip then
return
end
if p then
player:setpos(p)
end
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_look_horizontal(math.random(1, 180) / 100)
mcl_player.player_attached[name] = false
player:set_physics_override(1, 1, 1)
hud_flags.wielditem = true
mcl_player.player_set_animation(player, "stand" , 30)
-- lay down
else
mcl_beds.player[name] = 1
mcl_beds.pos[name] = pos
player_in_bed = player_in_bed + 1
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
local yaw, param2 = get_look_yaw(bed_pos)
player:set_look_horizontal(yaw)
local dir = minetest.facedir_to_dir(param2)
local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2}
player:set_physics_override(0, 0, 0)
player:setpos(p)
mcl_player.player_attached[name] = true
hud_flags.wielditem = false
mcl_player.player_set_animation(player, "lay" , 0)
end
player:hud_set_flags(hud_flags)
end
local function update_formspecs(finished)
local ges = #minetest.get_connected_players()
local form_n
local all_in_bed = ges == player_in_bed
if finished then
form_n = mcl_beds.formspec .. "label[2.7,11; Good morning.]"
else
form_n = mcl_beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) ..
" of " .. tostring(ges) .. " players are in bed]"
if all_in_bed and is_night_skip_enabled() then
form_n = form_n .. "button_exit[2,8;4,0.75;force;Force night skip]"
end
end
for name,_ in pairs(mcl_beds.player) do
minetest.show_formspec(name, "mcl_beds_form", form_n)
end
end
-- Public functions
function mcl_beds.kick_players()
for name, _ in pairs(mcl_beds.player) do
local player = minetest.get_player_by_name(name)
lay_down(player, nil, nil, false)
end
end
function mcl_beds.skip_night()
minetest.set_timeofday(0.25) -- tod = 6000
end
function mcl_beds.on_rightclick(pos, player)
local name = player:get_player_name()
local ppos = player:getpos()
local tod = minetest.get_timeofday() * 24000
-- Values taken from Minecraft Wiki with offset of +6000
if tod < 18541 and tod > 5458 then
if mcl_beds.player[name] then
lay_down(player, nil, nil, false)
end
minetest.chat_send_player(name, "You can only sleep at night.")
return
end
-- move to bed
if not mcl_beds.player[name] then
lay_down(player, ppos, pos)
mcl_beds.set_spawns() -- save respawn positions when entering bed
else
lay_down(player, nil, nil, false)
end
if not is_sp then
update_formspecs(false)
end
-- skip the night and let all players stand up
if check_in_beds() then
minetest.after(2, function()
if not is_sp then
update_formspecs(is_night_skip_enabled())
end
if is_night_skip_enabled() then
mcl_beds.skip_night()
mcl_beds.kick_players()
end
end)
end
end
-- Callbacks
-- Only register respawn callback if respawn enabled
if enable_respawn then
-- respawn player at bed if enabled and valid position is found
minetest.register_on_respawnplayer(function(player)
local name = player:get_player_name()
local pos = mcl_beds.spawn[name]
if pos then
player:setpos(pos)
return true
end
end)
end
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
lay_down(player, nil, nil, false, true)
mcl_beds.player[name] = nil
if check_in_beds() then
minetest.after(2, function()
update_formspecs(is_night_skip_enabled())
if is_night_skip_enabled() then
mcl_beds.skip_night()
mcl_beds.kick_players()
end
end)
end
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "mcl_beds_form" then
return
end
if fields.quit or fields.leave then
lay_down(player, nil, nil, false)
update_formspecs(false)
end
if fields.force then
update_formspecs(is_night_skip_enabled())
if is_night_skip_enabled() then
mcl_beds.skip_night()
mcl_beds.kick_players()
end
end
end)

View file

@ -0,0 +1,17 @@
mcl_beds = {}
mcl_beds.player = {}
mcl_beds.pos = {}
mcl_beds.spawn = {}
mcl_beds.formspec = "size[8,15;true]" ..
"bgcolor[#080808BB; true]" ..
"button_exit[2,12;4,0.75;leave;Leave Bed]"
local modpath = minetest.get_modpath("mcl_beds")
-- Load files
dofile(modpath .. "/functions.lua")
dofile(modpath .. "/api.lua")
dofile(modpath .. "/beds.lua")
dofile(modpath .. "/spawns.lua")

View file

@ -0,0 +1,60 @@
License of source code
----------------------
The MIT License (MIT)
Copyright (C) 2014-2016 BlockMen
Copyright (C) 2014-2016 Various Minetest developers and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
For more details:
https://opensource.org/licenses/MIT
Licenses of media (textures)
----------------------------
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Copyright (C) 2014-2016 BlockMen
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute
your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/

View file

@ -0,0 +1 @@
name = mcl_beds

View file

@ -0,0 +1,63 @@
local world_path = minetest.get_worldpath()
local org_file = world_path .. "/beds_spawns"
local file = world_path .. "/beds_spawns"
local bkwd = false
-- check for PA's beds mod spawns
local cf = io.open(world_path .. "/beds_player_spawns", "r")
if cf ~= nil then
io.close(cf)
file = world_path .. "/beds_player_spawns"
bkwd = true
end
function mcl_beds.save_spawns()
if not mcl_beds.spawn then
return
end
local data = {}
local output = io.open(org_file, "w")
for k, v in pairs(mcl_beds.spawn) do
table.insert(data, string.format("%.1f %.1f %.1f %s\n", v.x, v.y, v.z, k))
end
output:write(table.concat(data))
io.close(output)
end
function mcl_beds.read_spawns()
local spawns = mcl_beds.spawn
local input = io.open(file, "r")
if input and not bkwd then
repeat
local x = input:read("*n")
if x == nil then
break
end
local y = input:read("*n")
local z = input:read("*n")
local name = input:read("*l")
spawns[name:sub(2)] = {x = x, y = y, z = z}
until input:read(0) == nil
io.close(input)
elseif input and bkwd then
mcl_beds.spawn = minetest.deserialize(input:read("*all"))
input:close()
mcl_beds.save_spawns()
os.rename(file, file .. ".backup")
file = org_file
end
end
mcl_beds.read_spawns()
function mcl_beds.set_spawns()
for name,_ in pairs(mcl_beds.player) do
local player = minetest.get_player_by_name(name)
local p = player:getpos()
-- but don't change spawn location if borrowing a bed
if not minetest.is_protected(p, name) then
mcl_beds.spawn[name] = p
end
end
mcl_beds.save_spawns()
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB