Use mcl_playerphysics to handle player physics
[MineClone/MineClone2.git] / mods / ITEMS / mcl_beds / functions.lua
blob702a1d0c2c84c1b4d43d012eaf29107090a0ad0e
1 local pi = math.pi
2 local player_in_bed = 0
3 local is_sp = minetest.is_singleplayer()
4 local weather_mod = minetest.get_modpath("mcl_weather") ~= nil
6 -- Helper functions
8 local function get_look_yaw(pos)
9 local n = minetest.get_node(pos)
10 if n.param2 == 1 then
11 return pi / 2, n.param2
12 elseif n.param2 == 3 then
13 return -pi / 2, n.param2
14 elseif n.param2 == 0 then
15 return pi, n.param2
16 else
17 return 0, n.param2
18 end
19 end
21 local function is_night_skip_enabled()
22 local enable_night_skip = minetest.settings:get_bool("enable_bed_night_skip")
23 if enable_night_skip == nil then
24 enable_night_skip = true
25 end
26 return enable_night_skip
27 end
29 local function check_in_beds(players)
30 local in_bed = mcl_beds.player
31 if not players then
32 players = minetest.get_connected_players()
33 end
35 for n, player in ipairs(players) do
36 local name = player:get_player_name()
37 if not in_bed[name] then
38 return false
39 end
40 end
42 return #players > 0
43 end
45 -- These monsters do not prevent sleep
46 local monster_exceptions = {
47 ["mobs_mc:ghast"] = true,
48 ["mobs_mc:enderdragon"] = true,
49 ["mobs_mc:killer_bunny"] = true,
50 ["mobs_mc:slime_big"] = true,
51 ["mobs_mc:slime_small"] = true,
52 ["mobs_mc:slime_tiny"] = true,
53 ["mobs_mc:magma_cube_big"] = true,
54 ["mobs_mc:magma_cube_small"] = true,
55 ["mobs_mc:magma_cube_tiny"] = true,
56 ["mobs_mc:shulker"] = true,
59 local function lay_down(player, pos, bed_pos, state, skip)
60 local name = player:get_player_name()
61 local hud_flags = player:hud_get_flags()
63 if not player or not name then
64 return
65 end
67 if bed_pos then
68 -- No sleeping if too far away
69 if vector.distance(bed_pos, pos) > 2 then
70 minetest.chat_send_player(name, "You can't sleep, the bed's too far away!")
71 return
72 end
74 -- No sleeping if monsters nearby.
75 -- The exceptions above apply.
76 -- Zombie pigmen only prevent sleep while they are hostle.
77 local objs = minetest.get_objects_inside_radius(bed_pos, 8)
78 for _, obj in ipairs(objs) do
79 if obj ~= nil and not obj:is_player() then
80 local ent = obj:get_luaentity()
81 local mobname = ent.name
82 local def = minetest.registered_entities[mobname]
83 -- Approximation of monster detection range
84 if def._cmi_is_mob and ((mobname ~= "mobs_mc:pigman" and def.type == "monster" and not monster_exceptions[mobname]) or (mobname == "mobs_mc:pigman" and ent.state == "attack")) then
85 if math.abs(bed_pos.y - obj:get_pos().y) <= 5 then
86 minetest.chat_send_player(name, "You can't sleep now, monsters are nearby!")
87 end
88 return
89 end
90 end
91 end
92 end
94 -- stand up
95 if state ~= nil and not state then
96 local p = mcl_beds.pos[name] or nil
97 if mcl_beds.player[name] ~= nil then
98 mcl_beds.player[name] = nil
99 player_in_bed = player_in_bed - 1
101 -- skip here to prevent sending player specific changes (used for leaving players)
102 if skip then
103 return
105 if p then
106 player:setpos(p)
109 -- physics, eye_offset, etc
110 player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
111 player:set_look_horizontal(math.random(1, 180) / 100)
112 mcl_player.player_attached[name] = false
113 mcl_playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping")
114 mcl_playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping")
115 player:set_attribute("mcl_beds:sleeping", "false")
116 hud_flags.wielditem = true
117 mcl_player.player_set_animation(player, "stand" , 30)
119 -- lay down
120 else
121 mcl_beds.player[name] = 1
122 mcl_beds.pos[name] = pos
123 player_in_bed = player_in_bed + 1
125 -- physics, eye_offset, etc
126 player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
127 local yaw, param2 = get_look_yaw(bed_pos)
128 player:set_look_horizontal(yaw)
129 local dir = minetest.facedir_to_dir(param2)
130 local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2}
131 player:set_attribute("mcl_beds:sleeping", "true")
132 mcl_playerphysics.add_physics_factor(player, "speed", "mcl_beds:sleeping", 0)
133 mcl_playerphysics.add_physics_factor(player, "jump", "mcl_beds:sleeping", 0)
134 player:setpos(p)
135 mcl_player.player_attached[name] = true
136 hud_flags.wielditem = false
137 mcl_player.player_set_animation(player, "lay" , 0)
140 player:hud_set_flags(hud_flags)
143 local function update_formspecs(finished)
144 local ges = #minetest.get_connected_players()
145 local form_n
146 local all_in_bed = ges == player_in_bed
148 if finished then
149 form_n = mcl_beds.formspec .. "label[2.7,11; Good morning.]"
150 else
151 form_n = mcl_beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) ..
152 " of " .. tostring(ges) .. " players are in bed]"
155 for name,_ in pairs(mcl_beds.player) do
156 minetest.show_formspec(name, "mcl_beds_form", form_n)
160 -- Public functions
162 -- Handle environment stuff related to sleeping: skip night and thunderstorm
163 function mcl_beds.sleep()
164 local storm_skipped = mcl_beds.skip_thunderstorm()
165 -- Always clear weather
166 if weather_mod then
167 mcl_weather.change_weather("none")
169 if is_night_skip_enabled() then
170 if not storm_skipped then
171 mcl_beds.skip_night()
173 mcl_beds.kick_players()
177 function mcl_beds.kick_players()
178 for name, _ in pairs(mcl_beds.player) do
179 local player = minetest.get_player_by_name(name)
180 lay_down(player, nil, nil, false)
184 function mcl_beds.skip_night()
185 minetest.set_timeofday(0.25) -- tod = 6000
188 function mcl_beds.skip_thunderstorm()
189 -- Skip thunderstorm
190 if weather_mod and mcl_weather.get_weather() == "thunder" then
191 -- Sleep for a half day (=minimum thunderstorm duration)
192 minetest.set_timeofday((minetest.get_timeofday() + 0.5) % 1)
193 return true
195 return false
198 function mcl_beds.on_rightclick(pos, player)
199 -- Anti-Inception: Don't allow to sleep while you're sleeping
200 if player:get_attribute("mcl_beds:sleeping") == "true" then
201 return
203 if minetest.get_modpath("mcl_worlds") then
204 local dim = mcl_worlds.pos_to_dimension(pos)
205 if dim == "nether" or dim == "end" then
206 -- Bed goes BOOM in the Nether or End.
207 minetest.remove_node(pos)
208 if minetest.get_modpath("mcl_tnt") then
209 tnt.boom(pos, {radius = 4, damage_radius = 4})
211 return
214 local name = player:get_player_name()
215 local ppos = player:getpos()
216 local tod = minetest.get_timeofday() * 24000
218 -- Values taken from Minecraft Wiki with offset of +6000
219 if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then
220 if mcl_beds.player[name] then
221 lay_down(player, nil, nil, false)
223 minetest.chat_send_player(name, "You can only sleep at night or during a thunderstorm.")
224 return
227 -- move to bed
228 if not mcl_beds.player[name] then
229 lay_down(player, ppos, pos)
230 if minetest.get_modpath("mcl_spawn") then
231 mcl_spawn.set_spawn_pos(player, player:get_pos()) -- save respawn position when entering bed
233 else
234 lay_down(player, nil, nil, false)
237 if not is_sp then
238 update_formspecs(false)
241 -- skip the night and let all players stand up
242 if check_in_beds() then
243 minetest.after(5, function()
244 if not is_sp then
245 update_formspecs(is_night_skip_enabled())
247 mcl_beds.sleep()
248 end)
253 -- Callbacks
254 minetest.register_on_joinplayer(function(player)
255 if player:get_attribute("mcl_beds:sleeping") == "true" then
256 player:set_attribute("mcl_beds:sleeping", "false")
258 end)
260 minetest.register_on_leaveplayer(function(player)
261 local name = player:get_player_name()
262 lay_down(player, nil, nil, false, true)
263 mcl_beds.player[name] = nil
264 if check_in_beds() then
265 minetest.after(5, function()
266 update_formspecs(is_night_skip_enabled())
267 mcl_beds.sleep()
268 end)
270 end)
272 minetest.register_on_player_receive_fields(function(player, formname, fields)
273 if formname ~= "mcl_beds_form" then
274 return
276 if fields.quit or fields.leave then
277 lay_down(player, nil, nil, false)
278 update_formspecs(false)
281 if fields.force then
282 update_formspecs(is_night_skip_enabled())
283 mcl_beds.sleep()
285 end)