functions.lua 5.16 KB
Newer Older
1
local pi = math.pi
BlockMen's avatar
BlockMen committed
2
3
local player_in_bed = 0
local is_sp = minetest.is_singleplayer()
BlockMen's avatar
BlockMen committed
4
5
6
7
local enable_respawn = minetest.setting_getbool("enable_bed_respawn")
if enable_respawn == nil then
	enable_respawn = true
end
BlockMen's avatar
BlockMen committed
8

paramat's avatar
paramat committed
9
-- Helper functions
BlockMen's avatar
BlockMen committed
10
11
12
13

local function get_look_yaw(pos)
	local n = minetest.get_node(pos)
	if n.param2 == 1 then
paramat's avatar
paramat committed
14
		return pi / 2, n.param2
BlockMen's avatar
BlockMen committed
15
	elseif n.param2 == 3 then
paramat's avatar
paramat committed
16
		return -pi / 2, n.param2
BlockMen's avatar
BlockMen committed
17
	elseif n.param2 == 0 then
18
		return pi, n.param2
BlockMen's avatar
BlockMen committed
19
	else
20
		return 0, n.param2
BlockMen's avatar
BlockMen committed
21
22
23
	end
end

24
25
26
27
28
29
30
31
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

BlockMen's avatar
BlockMen committed
32
33
34
35
36
37
38
39
40
41
42
43
44
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

45
	return #players > 0
BlockMen's avatar
BlockMen committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
67
		if p then
BlockMen's avatar
BlockMen committed
68
69
70
71
			player:setpos(p)
		end

		-- physics, eye_offset, etc
paramat's avatar
paramat committed
72
		player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
73
		player:set_look_horizontal(math.random(1, 180) / 100)
BlockMen's avatar
BlockMen committed
74
75
76
77
78
79
80
81
82
83
84
85
		default.player_attached[name] = false
		player:set_physics_override(1, 1, 1)
		hud_flags.wielditem = true
		default.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
paramat's avatar
paramat committed
86
		player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
BlockMen's avatar
BlockMen committed
87
		local yaw, param2 = get_look_yaw(bed_pos)
88
		player:set_look_horizontal(yaw)
BlockMen's avatar
BlockMen committed
89
		local dir = minetest.facedir_to_dir(param2)
paramat's avatar
paramat committed
90
		local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2}
BlockMen's avatar
BlockMen committed
91
92
93
94
95
96
97
98
99
100
101
102
		player:set_physics_override(0, 0, 0)
		player:setpos(p)
		default.player_attached[name] = true
		hud_flags.wielditem = false
		default.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()
103
	local form_n
paramat's avatar
paramat committed
104
	local is_majority = (ges / 2) < player_in_bed
BlockMen's avatar
BlockMen committed
105
106

	if finished then
paramat's avatar
paramat committed
107
		form_n = beds.formspec .. "label[2.7,11; Good morning.]"
BlockMen's avatar
BlockMen committed
108
	else
paramat's avatar
paramat committed
109
110
		form_n = beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) ..
			" of " .. tostring(ges) .. " players are in bed]"
111
		if is_majority and is_night_skip_enabled() then
paramat's avatar
paramat committed
112
			form_n = form_n .. "button_exit[2,8;4,0.75;force;Force night skip]"
BlockMen's avatar
BlockMen committed
113
114
115
116
117
118
119
120
121
		end
	end

	for name,_ in pairs(beds.player) do
		minetest.show_formspec(name, "beds_form", form_n)
	end
end


paramat's avatar
paramat committed
122
-- Public functions
BlockMen's avatar
BlockMen committed
123
124

function beds.kick_players()
paramat's avatar
paramat committed
125
	for name, _ in pairs(beds.player) do
BlockMen's avatar
BlockMen committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
		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)
151
		beds.set_spawns() -- save respawn positions when entering bed
BlockMen's avatar
BlockMen committed
152
153
154
155
156
157
158
159
160
161
162
163
	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
164
165
166
167
168
				update_formspecs(is_night_skip_enabled())
			end
			if is_night_skip_enabled() then
				beds.skip_night()
				beds.kick_players()
BlockMen's avatar
BlockMen committed
169
170
171
172
173
174
			end
		end)
	end
end


paramat's avatar
paramat committed
175
-- Callbacks
176
177
178
179
180
181
182
183
184
185
186
187
-- 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
BlockMen's avatar
BlockMen committed
188
189
190
191
192
193
194

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()
195
196
197
198
199
			update_formspecs(is_night_skip_enabled())
			if is_night_skip_enabled() then
				beds.skip_night()
				beds.kick_players()
			end
BlockMen's avatar
BlockMen committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
		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
214
215
216
217
218
		update_formspecs(is_night_skip_enabled())
		if is_night_skip_enabled() then
			beds.skip_night()
			beds.kick_players()
		end
BlockMen's avatar
BlockMen committed
219
220
	end
end)