diff --git a/mods/beds/README.txt b/mods/beds/README.txt index 380239c597..cda6ebd92b 100644 --- a/mods/beds/README.txt +++ b/mods/beds/README.txt @@ -1,26 +1,26 @@ -Minetest mod "Beds" -======================= -version: 1.1 - - -License of source code: WTFPL ------------------------------ -author: BlockMen (2013) -original author: PilzAdam - -This program is free software. It comes without any warranty, to -the extent permitted by applicable law. You can redistribute it -and/or modify it under the terms of the Do What The Fuck You Want -To Public License, Version 2, as published by Sam Hocevar. See -http://sam.zoy.org/wtfpl/COPYING for more details. - - ---USING the mod-- ------------------- - -This mods implements Beds like known from Minecraft. You can use them to sleep at night to skip the time or to prevent attacks by evil mobs. - - -To sleep you have to "rightclick" on your bed. You can only sleep at night and get noticed when it is too early. - -After dying the player will respawn at the last bed he has slept. \ No newline at end of file +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. diff --git a/mods/beds/api.lua b/mods/beds/api.lua new file mode 100644 index 0000000000..a70fdb1390 --- /dev/null +++ b/mods/beds/api.lua @@ -0,0 +1,158 @@ + +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 + +function beds.register_bed(name, def) + minetest.register_node(name .. "_bottom", { + description = def.description, + inventory_image = def.inventory_image, + wield_image = def.wield_image, + drawtype = "nodebox", + tiles = def.tiles.bottom, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + stack_max = 1, + groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 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, + }, + + on_place = function(itemstack, placer, pointed_thing) + local under = pointed_thing.under + 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) + 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", + is_ground_content = false, + pointable = false, + groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2}, + sounds = def.sounds or mcl_sounds.node_sound_wood_defaults(), + drop = name .. "_bottom", + node_box = { + type = "fixed", + fixed = def.nodebox.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 diff --git a/mods/beds/beds.lua b/mods/beds/beds.lua new file mode 100644 index 0000000000..08ae844968 --- /dev/null +++ b/mods/beds/beds.lua @@ -0,0 +1,34 @@ +-- Simple shaped bed + +beds.register_bed("beds:bed", { + description = "Bed", + inventory_image = "beds_bed.png", + wield_image = "beds_bed.png", + tiles = { + bottom = { + "beds_bed_top_bottom.png^[transformR90", + "default_wood.png", + "beds_bed_side_bottom_r.png", + "beds_bed_side_bottom_r.png^[transformfx", + "blank.png", + "beds_bed_side_bottom.png" + }, + top = { + "beds_bed_top_top.png^[transformR90", + "default_wood.png", + "beds_bed_side_top_r.png", + "beds_bed_side_top_r.png^[transformfx", + "beds_bed_side_top.png", + "blank.png", + } + }, + nodebox = { + 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}, + }, + selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.06, 1.5}, + recipe = { + {"group:wool", "group:wool", "group:wool"}, + {"group:wood", "group:wood", "group:wood"} + }, +}) diff --git a/mods/beds/functions.lua b/mods/beds/functions.lua new file mode 100644 index 0000000000..05202cf675 --- /dev/null +++ b/mods/beds/functions.lua @@ -0,0 +1,220 @@ +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 = 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 = beds.pos[name] or nil + if beds.player[name] ~= nil then + 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 + beds.player[name] = 1 + 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 is_majority = (ges / 2) < player_in_bed + + if finished then + form_n = beds.formspec .. "label[2.7,11; Good morning.]" + else + form_n = beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) .. + " of " .. tostring(ges) .. " players are in bed]" + if is_majority 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(beds.player) do + minetest.show_formspec(name, "beds_form", form_n) + end +end + + +-- Public functions + +function beds.kick_players() + for name, _ in pairs(beds.player) do + local player = minetest.get_player_by_name(name) + lay_down(player, nil, nil, false) + end +end + +function beds.skip_night() + minetest.set_timeofday(0.23) +end + +function beds.on_rightclick(pos, player) + local name = player:get_player_name() + local ppos = player:getpos() + local tod = minetest.get_timeofday() + + if tod > 0.2 and tod < 0.805 then + if 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 beds.player[name] then + lay_down(player, ppos, pos) + 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 + beds.skip_night() + 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 = 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) + 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 + beds.skip_night() + beds.kick_players() + end + end) + end +end) + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "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 + beds.skip_night() + beds.kick_players() + end + end +end) diff --git a/mods/beds/init.lua b/mods/beds/init.lua index ce1732c23a..8b25890177 100644 --- a/mods/beds/init.lua +++ b/mods/beds/init.lua @@ -1,263 +1,17 @@ -local player_in_bed = 0 -local guy -local hand -local old_yaw = 0 - -local function get_dir(pos) - local btop = "beds:bed_top" - if minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z}).name == btop then - return 7.9 - elseif minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z}).name == btop then - return 4.75 - elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1}).name == btop then - return 3.15 - elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1}).name == btop then - return 6.28 - end -end - -local function plock(start, max, tick, player, yaw) - if start+tick < max then - player:set_look_pitch(-1.2) - player:set_look_yaw(yaw) - minetest.after(tick, plock, start+tick, max, tick, player, yaw) - else - player:set_look_pitch(0) - if old_yaw ~= 0 then minetest.after(0.1+tick, function() player:set_look_yaw(old_yaw) end) end - end -end - -local function exit(pos) - local npos = minetest.find_node_near(pos, 1, "beds:bed_bottom") - if npos ~= nil then pos = npos end - if minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z}).name == "air" then - return {x=pos.x+1,y=pos.y,z=pos.z} - elseif minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z}).name == "air" then - return {x=pos.x-1,y=pos.y,z=pos.z} - elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1}).name == "air" then - return {x=pos.x,y=pos.y,z=pos.z+1} - elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1}).name == "air" then - return {x=pos.x,y=pos.y,z=pos.z-1} - else - return {x=pos.x,y=pos.y,z=pos.z} - end -end - -minetest.register_node("beds:bed_bottom", { - description = "Bed", - inventory_image = "beds_bed.png", - wield_image = "beds_bed.png", - wield_scale = {x=1.5,y=1.5,z=1.5}, - drawtype = "nodebox", - is_ground_content = false, - tiles = {"beds_bed_top_bottom.png^[transformR90", "default_wood.png", "beds_bed_side_bottom_r.png", "beds_bed_side_bottom_r.png^[transformfx", "beds_bed_leer.png", "beds_bed_side_bottom.png"}, - paramtype = "light", - paramtype2 = "facedir", - stack_max = 1, - groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,bed=1,deco_block=1}, - sounds = mcl_sounds.node_sound_wood_defaults(), - node_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5}, - }, - selection_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 1.5}, - - }, - - after_place_node = function(pos, placer, itemstack) - local node = minetest.get_node(pos) - local param2 = node.param2 - local npos = {x=pos.x, y=pos.y, z=pos.z} - if param2 == 0 then - npos.z = npos.z+1 - elseif param2 == 1 then - npos.x = npos.x+1 - elseif param2 == 2 then - npos.z = npos.z-1 - elseif param2 == 3 then - npos.x = npos.x-1 - end - if minetest.registered_nodes[minetest.get_node(npos).name].buildable_to == true and minetest.get_node({x=npos.x, y=npos.y-1, z=npos.z}).name ~= "air" then - minetest.set_node(npos, {name="beds:bed_top", param2 = param2}) - else - minetest.dig_node(pos) - return true - end - end, - - on_destruct = function(pos) - pos = minetest.find_node_near(pos, 1, "beds:bed_top") - if pos ~= nil then minetest.remove_node(pos) end - end, - - on_rightclick = function(pos, node, clicker, itemstack) - if not clicker:is_player() then - return - end - - if minetest.get_timeofday() > 0.2 and minetest.get_timeofday() < 0.805 then - minetest.chat_send_all("You can only sleep at night") - return - else - clicker:set_physics_override(0,0,0) - old_yaw = clicker:get_look_yaw() - guy = clicker - clicker:set_look_yaw(get_dir(pos)) - minetest.chat_send_all("Good night") - plock(0,2,0.1,clicker, get_dir(pos)) - end - - if not clicker:get_player_control().sneak then - local meta = minetest.get_meta(pos) - local param2 = node.param2 - if param2 == 0 then - pos.z = pos.z+1 - elseif param2 == 1 then - pos.x = pos.x+1 - elseif param2 == 2 then - pos.z = pos.z-1 - elseif param2 == 3 then - pos.x = pos.x-1 - end - if clicker:get_player_name() == meta:get_string("player") then - if param2 == 0 then - pos.x = pos.x-1 - elseif param2 == 1 then - pos.z = pos.z+1 - elseif param2 == 2 then - pos.x = pos.x+1 - elseif param2 == 3 then - pos.z = pos.z-1 - end - pos.y = pos.y-0.5 - clicker:setpos(pos) - meta:set_string("player", "") - player_in_bed = player_in_bed-1 - elseif meta:get_string("player") == "" then - pos.y = pos.y-0.5 - clicker:setpos(pos) - meta:set_string("player", clicker:get_player_name()) - player_in_bed = player_in_bed+1 - end - end - end -}) - -minetest.register_node("beds:bed_top", { - drawtype = "nodebox", - tiles = {"beds_bed_top_top.png^[transformR90", "beds_bed_leer.png", "beds_bed_side_top_r.png", "beds_bed_side_top_r.png^[transformfx", "beds_bed_side_top.png", "beds_bed_leer.png"}, - paramtype = "light", - paramtype2 = "facedir", - is_ground_content = false, - groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,not_in_creative_inventory=1}, - sounds = mcl_sounds.node_sound_wood_defaults(), - node_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5}, - }, - selection_box = { - type = "fixed", - fixed = {0, 0, 0, 0, 0, 0}, - }, -}) - -minetest.register_alias("beds:bed", "beds:bed_bottom") - -minetest.register_craft({ - output = "beds:bed", - recipe = { - {"group:wool", "group:wool", "group:wool", }, - {"group:wood", "group:wood", "group:wood", } - } -}) - -local beds_player_spawns = {} -local file = io.open(minetest.get_worldpath().."/beds_player_spawns", "r") -if file then - beds_player_spawns = minetest.deserialize(file:read("*all")) - file:close() -end - -local timer = 0 -local wait = false -minetest.register_globalstep(function(dtime) - if timer<2 then - timer = timer+dtime - return - end - timer = 0 - - local players = #minetest.get_connected_players() - if players == player_in_bed and players ~= 0 then - if minetest.get_timeofday() < 0.2 or minetest.get_timeofday() > 0.805 then - if not wait then - minetest.after(2, function() - minetest.set_timeofday(0.23) - wait = false - guy:set_physics_override(1,1,1) - guy:setpos(exit(guy:getpos())) - - end) - wait = true - for _,player in ipairs(minetest.get_connected_players()) do - beds_player_spawns[player:get_player_name()] = player:getpos() - end - local file = io.open(minetest.get_worldpath().."/beds_player_spawns", "w") - if file then - file:write(minetest.serialize(beds_player_spawns)) - file:close() - end - end - end - end -end) - -minetest.register_on_respawnplayer(function(player) - local name = player:get_player_name() - if beds_player_spawns[name] then - player:setpos(beds_player_spawns[name]) - return true - end -end) - -minetest.register_abm({ - nodenames = {"beds:bed_bottom"}, - interval = 1, - chance = 1, - action = function(pos, node) - local meta = minetest.get_meta(pos) - if meta:get_string("player") ~= "" then - local param2 = node.param2 - if param2 == 0 then - pos.z = pos.z+1 - elseif param2 == 1 then - pos.x = pos.x+1 - elseif param2 == 2 then - pos.z = pos.z-1 - elseif param2 == 3 then - pos.x = pos.x-1 - end - local player = minetest.get_player_by_name(meta:get_string("player")) - if player == nil then - meta:set_string("player", "") - player_in_bed = player_in_bed-1 - return - end - local player_pos = player:getpos() - player_pos.x = math.floor(0.5+player_pos.x) - player_pos.y = math.floor(0.5+player_pos.y) - player_pos.z = math.floor(0.5+player_pos.z) - if pos.x ~= player_pos.x or pos.y ~= player_pos.y or pos.z ~= player_pos.z then - meta:set_string("player", "") - player_in_bed = player_in_bed-1 - return - end - end - end -}) - -if minetest.setting_get("log_mods") then - minetest.log("action", "beds loaded") -end +beds = {} +beds.player = {} +beds.pos = {} +beds.spawn = {} + +beds.formspec = "size[8,15;true]" .. + "bgcolor[#080808BB; true]" .. + "button_exit[2,12;4,0.75;leave;Leave Bed]" + +local modpath = minetest.get_modpath("beds") + +-- Load files + +dofile(modpath .. "/functions.lua") +dofile(modpath .. "/api.lua") +dofile(modpath .. "/beds.lua") +dofile(modpath .. "/spawns.lua") diff --git a/mods/beds/license.txt b/mods/beds/license.txt new file mode 100644 index 0000000000..0494b36b4f --- /dev/null +++ b/mods/beds/license.txt @@ -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/ diff --git a/mods/beds/spawns.lua b/mods/beds/spawns.lua new file mode 100644 index 0000000000..70bfb38bbf --- /dev/null +++ b/mods/beds/spawns.lua @@ -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 beds.save_spawns() + if not beds.spawn then + return + end + local data = {} + local output = io.open(org_file, "w") + for k, v in pairs(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 beds.read_spawns() + local spawns = 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 + beds.spawn = minetest.deserialize(input:read("*all")) + input:close() + beds.save_spawns() + os.rename(file, file .. ".backup") + file = org_file + end +end + +beds.read_spawns() + +function beds.set_spawns() + for name,_ in pairs(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 + beds.spawn[name] = p + end + end + beds.save_spawns() +end