Default/functions: Reduce lavacooling ABM/sound overload
[oweals/minetest_game.git] / mods / beds / functions.lua
1 local player_in_bed = 0
2 local is_sp = minetest.is_singleplayer()
3 local enable_respawn = minetest.setting_getbool("enable_bed_respawn")
4 if enable_respawn == nil then
5         enable_respawn = true
6 end
7
8
9 -- helper functions
10
11 local function get_look_yaw(pos)
12         local n = minetest.get_node(pos)
13         if n.param2 == 1 then
14                 return 7.9, n.param2
15         elseif n.param2 == 3 then
16                 return 4.75, n.param2
17         elseif n.param2 == 0 then
18                 return 3.15, n.param2
19         else
20                 return 6.28, n.param2
21         end
22 end
23
24 local function check_in_beds(players)
25         local in_bed = beds.player
26         if not players then
27                 players = minetest.get_connected_players()
28         end
29
30         for n, player in ipairs(players) do
31                 local name = player:get_player_name()
32                 if not in_bed[name] then
33                         return false
34                 end
35         end
36
37         return #players > 0
38 end
39
40 local function lay_down(player, pos, bed_pos, state, skip)
41         local name = player:get_player_name()
42         local hud_flags = player:hud_get_flags()
43
44         if not player or not name then
45                 return
46         end
47
48         -- stand up
49         if state ~= nil and not state then
50                 local p = beds.pos[name] or nil
51                 if beds.player[name] ~= nil then
52                         beds.player[name] = nil
53                         player_in_bed = player_in_bed - 1
54                 end
55                 -- skip here to prevent sending player specific changes (used for leaving players)
56                 if skip then
57                         return
58                 end
59                 if p then 
60                         player:setpos(p)
61                 end
62
63                 -- physics, eye_offset, etc
64                 player:set_eye_offset({x=0,y=0,z=0}, {x=0,y=0,z=0})
65                 player:set_look_yaw(math.random(1, 180)/100)
66                 default.player_attached[name] = false
67                 player:set_physics_override(1, 1, 1)
68                 hud_flags.wielditem = true
69                 default.player_set_animation(player, "stand" , 30)
70
71         -- lay down
72         else
73                 beds.player[name] = 1
74                 beds.pos[name] = pos
75                 player_in_bed = player_in_bed + 1
76
77                 -- physics, eye_offset, etc
78                 player:set_eye_offset({x=0,y=-13,z=0}, {x=0,y=0,z=0})
79                 local yaw, param2 = get_look_yaw(bed_pos)
80                 player:set_look_yaw(yaw)
81                 local dir = minetest.facedir_to_dir(param2)
82                 local p = {x=bed_pos.x+dir.x/2,y=bed_pos.y,z=bed_pos.z+dir.z/2}
83                 player:set_physics_override(0, 0, 0)
84                 player:setpos(p)
85                 default.player_attached[name] = true
86                 hud_flags.wielditem = false
87                 default.player_set_animation(player, "lay" , 0)
88         end
89
90         player:hud_set_flags(hud_flags)
91 end
92
93 local function update_formspecs(finished)
94         local ges = #minetest.get_connected_players()
95         local form_n = ""
96         local is_majority = (ges/2) < player_in_bed
97
98         if finished then
99                 form_n = beds.formspec ..
100                         "label[2.7,11; Good morning.]"
101         else
102                 form_n = beds.formspec ..
103                         "label[2.2,11;"..tostring(player_in_bed).." of "..tostring(ges).." players are in bed]" 
104                 if is_majority then
105                         form_n = form_n ..
106                                 "button_exit[2,8;4,0.75;force;Force night skip]"
107                 end
108         end
109
110         for name,_ in pairs(beds.player) do
111                 minetest.show_formspec(name, "beds_form", form_n)
112         end
113 end
114
115
116 -- public functions
117
118 function beds.kick_players()
119         for name,_ in pairs(beds.player) do
120                 local player = minetest.get_player_by_name(name)
121                 lay_down(player, nil, nil, false)
122         end
123 end
124
125 function beds.skip_night()
126         minetest.set_timeofday(0.23)
127         beds.set_spawns()
128 end
129
130 function beds.on_rightclick(pos, player)
131         local name = player:get_player_name()
132         local ppos = player:getpos()
133         local tod = minetest.get_timeofday()
134
135         if tod > 0.2 and tod < 0.805 then
136                 if beds.player[name] then
137                         lay_down(player, nil, nil, false)
138                 end
139                 minetest.chat_send_player(name, "You can only sleep at night.")
140                 return
141         end
142
143         -- move to bed
144         if not beds.player[name] then
145                 lay_down(player, ppos, pos)
146         else
147                 lay_down(player, nil, nil, false)
148         end
149
150         if not is_sp then
151                 update_formspecs(false)
152         end
153
154         -- skip the night and let all players stand up
155         if check_in_beds() then
156                 minetest.after(2, function()
157                         beds.skip_night()
158                         if not is_sp then
159                                 update_formspecs(true)
160                         end
161                         beds.kick_players()
162                 end)
163         end
164 end
165
166
167 -- callbacks
168
169 minetest.register_on_joinplayer(function(player)
170         beds.read_spawns()
171 end)
172
173 -- respawn player at bed if enabled and valid position is found
174 minetest.register_on_respawnplayer(function(player)
175         if not enable_respawn then
176                 return false
177         end
178         local name = player:get_player_name()
179         local pos = beds.spawn[name] or nil
180         if pos then
181                 player:setpos(pos)
182                 return true
183         end
184 end)
185
186 minetest.register_on_leaveplayer(function(player)
187         local name = player:get_player_name()
188         lay_down(player, nil, nil, false, true)
189         beds.player[name] = nil
190         if check_in_beds() then
191                 minetest.after(2, function()
192                         beds.skip_night()
193                         update_formspecs(true)
194                         beds.kick_players()
195                 end)
196         end
197 end)
198
199 minetest.register_on_player_receive_fields(function(player, formname, fields)
200         if formname ~= "beds_form" then
201                 return
202         end
203         if fields.quit or fields.leave then
204                 lay_down(player, nil, nil, false)
205                 update_formspecs(false)
206         end
207
208         if fields.force then
209                 beds.skip_night()
210                 update_formspecs(true)
211                 beds.kick_players()
212         end
213 end)