Emit liquid sound if the player walks in liquid (#6040)
[oweals/minetest.git] / src / localplayer.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "localplayer.h"
21
22 #include "event.h"
23 #include "collision.h"
24 #include "nodedef.h"
25 #include "settings.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "client.h"
29 #include "content_cao.h"
30
31 /*
32         LocalPlayer
33 */
34
35 LocalPlayer::LocalPlayer(Client *client, const char *name):
36         Player(name, client->idef()),
37         m_client(client)
38 {
39 }
40
41 LocalPlayer::~LocalPlayer()
42 {
43 }
44
45 static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
46 {
47         aabb3f b_max;
48         b_max.reset(-BS, -BS, -BS);
49         for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
50                         it != nodeboxes.end(); ++it) {
51                 aabb3f box = *it;
52                 if (box.MaxEdge.Y > b_max.MaxEdge.Y)
53                         b_max = box;
54                 else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
55                         b_max.addInternalBox(box);
56         }
57         return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
58 }
59
60 #define GETNODE(map, p3, v2, y, valid) \
61         (map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
62
63 // pos is the node the player is standing inside(!)
64 static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
65 {
66         // Detects a structure known as "sneak ladder" or "sneak elevator"
67         // that relies on bugs to provide a fast means of vertical transportation,
68         // the bugs have since been fixed but this function remains to keep it working.
69         // NOTE: This is just entirely a huge hack and causes way too many problems.
70         bool is_valid_position;
71         MapNode node;
72         // X/Z vectors for 4 neighboring nodes
73         static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
74
75         for (u16 i = 0; i < ARRLEN(vecs); i++) {
76                 const v2s16 vec = vecs[i];
77
78                 // walkability of bottom & top node should differ
79                 node = GETNODE(map, pos, vec, 0, &is_valid_position);
80                 if (!is_valid_position)
81                         continue;
82                 bool w = nodemgr->get(node).walkable;
83                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
84                 if (!is_valid_position || w == nodemgr->get(node).walkable)
85                         continue;
86
87                 // check one more node above OR below with corresponding walkability
88                 node = GETNODE(map, pos, vec, -1, &is_valid_position);
89                 bool ok = is_valid_position && w != nodemgr->get(node).walkable;
90                 if (!ok) {
91                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
92                         ok = is_valid_position && w == nodemgr->get(node).walkable;
93                 }
94
95                 if (ok)
96                         return true;
97         }
98
99         return false;
100 }
101
102 static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
103 {
104         bool is_valid_position;
105         MapNode node;
106         // X/Z vectors for 4 neighboring nodes
107         static const v2s16 vecs[] = {v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1)};
108
109         for (u16 i = 0; i < ARRLEN(vecs); i++) {
110                 const v2s16 vec = vecs[i];
111
112                 node = GETNODE(map, pos, vec, 1, &is_valid_position);
113                 if (is_valid_position && nodemgr->get(node).walkable) {
114                         // Ledge exists
115                         node = GETNODE(map, pos, vec, 2, &is_valid_position);
116                         if (is_valid_position && !nodemgr->get(node).walkable)
117                                 // Space above ledge exists
118                                 return true;
119                 }
120         }
121
122         return false;
123 }
124
125 #undef GETNODE
126
127 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
128                 std::vector<CollisionInfo> *collision_info)
129 {
130         // Temporary option for old move code
131         if (!physics_override_new_move) {
132                 old_move(dtime, env, pos_max_d, collision_info);
133                 return;
134         }
135
136         Map *map = &env->getMap();
137         INodeDefManager *nodemgr = m_client->ndef();
138
139         v3f position = getPosition();
140
141         // Copy parent position if local player is attached
142         if(isAttached)
143         {
144                 setPosition(overridePosition);
145                 m_sneak_node_exists = false;
146                 return;
147         }
148
149         // Skip collision detection if noclip mode is used
150         bool fly_allowed = m_client->checkLocalPrivilege("fly");
151         bool noclip = m_client->checkLocalPrivilege("noclip") &&
152                 g_settings->getBool("noclip");
153         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
154         if (free_move) {
155                 position += m_speed * dtime;
156                 setPosition(position);
157                 m_sneak_node_exists = false;
158                 return;
159         }
160
161         /*
162                 Collision detection
163         */
164
165         bool is_valid_position;
166         MapNode node;
167         v3s16 pp;
168
169         /*
170                 Check if player is in liquid (the oscillating value)
171         */
172
173         // If in liquid, the threshold of coming out is at higher y
174         if (in_liquid)
175         {
176                 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
177                 node = map->getNodeNoEx(pp, &is_valid_position);
178                 if (is_valid_position) {
179                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
180                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
181                 } else {
182                         in_liquid = false;
183                 }
184         }
185         // If not in liquid, the threshold of going in is at lower y
186         else
187         {
188                 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
189                 node = map->getNodeNoEx(pp, &is_valid_position);
190                 if (is_valid_position) {
191                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
192                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
193                 } else {
194                         in_liquid = false;
195                 }
196         }
197
198
199         /*
200                 Check if player is in liquid (the stable value)
201         */
202         pp = floatToInt(position + v3f(0,0,0), BS);
203         node = map->getNodeNoEx(pp, &is_valid_position);
204         if (is_valid_position) {
205                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
206         } else {
207                 in_liquid_stable = false;
208         }
209
210         /*
211                 Check if player is climbing
212         */
213
214
215         pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
216         v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
217         node = map->getNodeNoEx(pp, &is_valid_position);
218         bool is_valid_position2;
219         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
220
221         if (!(is_valid_position && is_valid_position2)) {
222                 is_climbing = false;
223         } else {
224                 is_climbing = (nodemgr->get(node.getContent()).climbable
225                                 || nodemgr->get(node2.getContent()).climbable) && !free_move;
226         }
227
228
229         /*
230                 Collision uncertainty radius
231                 Make it a bit larger than the maximum distance of movement
232         */
233         //f32 d = pos_max_d * 1.1;
234         // A fairly large value in here makes moving smoother
235         f32 d = 0.15*BS;
236
237         // This should always apply, otherwise there are glitches
238         sanity_check(d > pos_max_d);
239
240         // Max. distance (X, Z) over border for sneaking determined by collision box
241         // * 0.49 to keep the center just barely on the node
242         v3f sneak_max = m_collisionbox.getExtent() * 0.49;
243         if (m_sneak_ladder_detected) {
244                 // restore legacy behaviour (this makes the m_speed.Y hack necessary)
245                 sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
246         }
247
248         /*
249                 If sneaking, keep in range from the last walked node and don't
250                 fall off from it
251         */
252         if (control.sneak && m_sneak_node_exists &&
253                         !(fly_allowed && g_settings->getBool("free_move")) &&
254                         !in_liquid && !is_climbing &&
255                         physics_override_sneak) {
256                 const v3f sn_f = intToFloat(m_sneak_node, BS);
257                 const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
258                 const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
259                 const v3f old_pos = position;
260                 const v3f old_speed = m_speed;
261
262                 position.X = rangelim(position.X,
263                                 bmin.X - sneak_max.X, bmax.X + sneak_max.X);
264                 position.Z = rangelim(position.Z,
265                                 bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
266
267                 if (position.X != old_pos.X)
268                         m_speed.X = 0;
269                 if (position.Z != old_pos.Z)
270                         m_speed.Z = 0;
271
272                 // Because we keep the player collision box on the node, limiting
273                 // position.Y is not necessary but useful to prevent players from
274                 // being inside a node if sneaking on e.g. the lower part of a stair
275                 if (!m_sneak_ladder_detected) {
276                         position.Y = MYMAX(position.Y, bmax.Y);
277                 } else {
278                         // legacy behaviour that sometimes causes some weird slow sinking
279                         m_speed.Y = MYMAX(m_speed.Y, 0);
280                 }
281
282                 if (collision_info != NULL &&
283                                 m_speed.Y - old_speed.Y > BS) {
284                         // Collide with sneak node, report fall damage
285                         CollisionInfo sn_info;
286                         sn_info.node_p = m_sneak_node;
287                         sn_info.old_speed = old_speed;
288                         sn_info.new_speed = m_speed;
289                         collision_info->push_back(sn_info);
290                 }
291         }
292
293         // TODO: this shouldn't be hardcoded but transmitted from server
294         float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
295
296 #ifdef __ANDROID__
297         player_stepheight += (0.6f * BS);
298 #endif
299
300         v3f accel_f = v3f(0,0,0);
301
302         collisionMoveResult result = collisionMoveSimple(env, m_client,
303                 pos_max_d, m_collisionbox, player_stepheight, dtime,
304                 &position, &m_speed, accel_f);
305
306         /*
307                 If the player's feet touch the topside of any node, this is
308                 set to true.
309
310                 Player is allowed to jump when this is true.
311         */
312         bool touching_ground_was = touching_ground;
313         touching_ground = result.touching_ground;
314
315         // We want the top of the sneak node to be below the players feet
316         f32 position_y_mod;
317         if (m_sneak_node_exists)
318                 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
319         else
320                 position_y_mod = (0.5 - 0.05) * BS;
321         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
322         /*
323                 Check the nodes under the player to see from which node the
324                 player is sneaking from, if any.  If the node from under
325                 the player has been removed, the player falls.
326         */
327         if (m_sneak_node_exists &&
328                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
329                         m_old_node_below_type != "air") {
330                 // Old node appears to have been removed; that is,
331                 // it wasn't air before but now it is
332                 m_need_to_get_new_sneak_node = false;
333                 m_sneak_node_exists = false;
334         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
335                 // We are on something, so make sure to recalculate the sneak
336                 // node.
337                 m_need_to_get_new_sneak_node = true;
338         }
339
340         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
341                 v2f player_p2df(position.X, position.Z);
342                 f32 min_distance_f = 100000.0 * BS;
343                 v3s16 new_sneak_node = m_sneak_node;
344                 for(s16 x=-1; x<=1; x++)
345                 for(s16 z=-1; z<=1; z++)
346                 {
347                         v3s16 p = current_node + v3s16(x,0,z);
348                         v3f pf = intToFloat(p, BS);
349                         v2f node_p2df(pf.X, pf.Z);
350                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
351
352                         if (distance_f > min_distance_f ||
353                                         fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
354                                         fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
355                                 continue;
356
357
358                         // The node to be sneaked on has to be walkable
359                         node = map->getNodeNoEx(p, &is_valid_position);
360                         if (!is_valid_position || !nodemgr->get(node).walkable)
361                                 continue;
362                         // And the node(s) above have to be nonwalkable
363                         bool ok = true;
364                         if (!physics_override_sneak_glitch) {
365                                 u16 height = ceilf(
366                                                 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
367                                 );
368                                 for (u16 y = 1; y <= height; y++) {
369                                         node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
370                                         if (!is_valid_position || nodemgr->get(node).walkable) {
371                                                 ok = false;
372                                                 break;
373                                         }
374                                 }
375                         } else {
376                                 // legacy behaviour: check just one node
377                                 node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
378                                 ok = is_valid_position && !nodemgr->get(node).walkable;
379                         }
380                         if (!ok)
381                                 continue;
382
383                         min_distance_f = distance_f;
384                         new_sneak_node = p;
385                 }
386
387                 bool sneak_node_found = (min_distance_f < 100000.0 * BS);
388                 m_sneak_node = new_sneak_node;
389                 m_sneak_node_exists = sneak_node_found;
390
391                 if (sneak_node_found) {
392                         // Update saved top bounding box of sneak node
393                         MapNode n = map->getNodeNoEx(m_sneak_node);
394                         std::vector<aabb3f> nodeboxes;
395                         n.getCollisionBoxes(nodemgr, &nodeboxes);
396                         m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
397
398                         m_sneak_ladder_detected = physics_override_sneak_glitch &&
399                                         detectSneakLadder(map, nodemgr, floatToInt(position, BS));
400                 } else {
401                         m_sneak_ladder_detected = false;
402                 }
403         }
404
405         /*
406                 If 'sneak glitch' enabled detect ledge for old sneak-jump
407                 behaviour of climbing onto a ledge 2 nodes up.
408         */
409         if (physics_override_sneak_glitch && control.sneak && control.jump)
410                 m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
411
412         /*
413                 Set new position but keep sneak node set
414         */
415         bool sneak_node_exists = m_sneak_node_exists;
416         setPosition(position);
417         m_sneak_node_exists = sneak_node_exists;
418
419         /*
420                 Report collisions
421         */
422
423         // Dont report if flying
424         if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
425                 for(size_t i=0; i<result.collisions.size(); i++) {
426                         const CollisionInfo &info = result.collisions[i];
427                         collision_info->push_back(info);
428                 }
429         }
430
431         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
432                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
433                 m_client->event()->put(e);
434
435                 // Set camera impact value to be used for view bobbing
436                 camera_impact = getSpeed().Y * -1;
437         }
438
439         {
440                 camera_barely_in_ceiling = false;
441                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
442                 MapNode n = map->getNodeNoEx(camera_np);
443                 if(n.getContent() != CONTENT_IGNORE){
444                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
445                                 camera_barely_in_ceiling = true;
446                         }
447                 }
448         }
449
450         /*
451                 Update the node last under the player
452         */
453         m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
454         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
455
456         /*
457                 Check properties of the node on which the player is standing
458         */
459         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
460         // Determine if jumping is possible
461         m_can_jump = touching_ground && !in_liquid;
462         if (itemgroup_get(f.groups, "disable_jump"))
463                 m_can_jump = false;
464         else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
465                 m_can_jump = true;
466
467         // Jump key pressed while jumping off from a bouncy block
468         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
469                 m_speed.Y >= -0.5 * BS) {
470                 float jumpspeed = movement_speed_jump * physics_override_jump;
471                 if (m_speed.Y > 1) {
472                         // Reduce boost when speed already is high
473                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
474                 } else {
475                         m_speed.Y += jumpspeed;
476                 }
477                 setSpeed(m_speed);
478                 m_can_jump = false;
479         }
480 }
481
482 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
483 {
484         move(dtime, env, pos_max_d, NULL);
485 }
486
487 void LocalPlayer::applyControl(float dtime)
488 {
489         // Clear stuff
490         swimming_vertical = false;
491
492         setPitch(control.pitch);
493         setYaw(control.yaw);
494
495         // Nullify speed and don't run positioning code if the player is attached
496         if(isAttached)
497         {
498                 setSpeed(v3f(0,0,0));
499                 return;
500         }
501
502         v3f move_direction = v3f(0,0,1);
503         move_direction.rotateXZBy(getYaw());
504
505         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
506         v3f speedV = v3f(0,0,0); // Vertical (Y)
507
508         bool fly_allowed = m_client->checkLocalPrivilege("fly");
509         bool fast_allowed = m_client->checkLocalPrivilege("fast");
510
511         bool free_move = fly_allowed && g_settings->getBool("free_move");
512         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
513         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
514         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
515         bool continuous_forward = g_settings->getBool("continuous_forward");
516         bool always_fly_fast = g_settings->getBool("always_fly_fast");
517
518         // Whether superspeed mode is used or not
519         bool superspeed = false;
520
521         if (always_fly_fast && free_move && fast_move)
522                 superspeed = true;
523
524         // Old descend control
525         if(g_settings->getBool("aux1_descends"))
526         {
527                 // If free movement and fast movement, always move fast
528                 if(free_move && fast_move)
529                         superspeed = true;
530
531                 // Auxiliary button 1 (E)
532                 if(control.aux1)
533                 {
534                         if(free_move)
535                         {
536                                 // In free movement mode, aux1 descends
537                                 if(fast_move)
538                                         speedV.Y = -movement_speed_fast;
539                                 else
540                                         speedV.Y = -movement_speed_walk;
541                         }
542                         else if(in_liquid || in_liquid_stable)
543                         {
544                                 speedV.Y = -movement_speed_walk;
545                                 swimming_vertical = true;
546                         }
547                         else if(is_climbing)
548                         {
549                                 speedV.Y = -movement_speed_climb;
550                         }
551                         else
552                         {
553                                 // If not free movement but fast is allowed, aux1 is
554                                 // "Turbo button"
555                                 if(fast_move)
556                                         superspeed = true;
557                         }
558                 }
559         }
560         // New minecraft-like descend control
561         else
562         {
563                 // Auxiliary button 1 (E)
564                 if(control.aux1)
565                 {
566                         if(!is_climbing)
567                         {
568                                 // aux1 is "Turbo button"
569                                 if(fast_move)
570                                         superspeed = true;
571                         }
572                 }
573
574                 if(control.sneak)
575                 {
576                         if(free_move)
577                         {
578                                 // In free movement mode, sneak descends
579                                 if (fast_move && (control.aux1 || always_fly_fast))
580                                         speedV.Y = -movement_speed_fast;
581                                 else
582                                         speedV.Y = -movement_speed_walk;
583                         }
584                         else if(in_liquid || in_liquid_stable)
585                         {
586                                 if(fast_climb)
587                                         speedV.Y = -movement_speed_fast;
588                                 else
589                                         speedV.Y = -movement_speed_walk;
590                                 swimming_vertical = true;
591                         }
592                         else if(is_climbing)
593                         {
594                                 if(fast_climb)
595                                         speedV.Y = -movement_speed_fast;
596                                 else
597                                         speedV.Y = -movement_speed_climb;
598                         }
599                 }
600         }
601
602         if (continuous_forward)
603                 speedH += move_direction;
604
605         if (control.up) {
606                 if (continuous_forward) {
607                         if (fast_move)
608                                 superspeed = true;
609                 } else {
610                         speedH += move_direction;
611                 }
612         }
613         if (control.down) {
614                 speedH -= move_direction;
615         }
616         if (!control.up && !control.down) {
617                 speedH -= move_direction *
618                         (control.forw_move_joystick_axis / 32767.f);
619         }
620         if (control.left) {
621                 speedH += move_direction.crossProduct(v3f(0,1,0));
622         }
623         if (control.right) {
624                 speedH += move_direction.crossProduct(v3f(0,-1,0));
625         }
626         if (!control.left && !control.right) {
627                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
628                         (control.sidew_move_joystick_axis / 32767.f);
629         }
630         if(control.jump)
631         {
632                 if (free_move) {
633                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
634                                 if (fast_move)
635                                         speedV.Y = movement_speed_fast;
636                                 else
637                                         speedV.Y = movement_speed_walk;
638                         } else {
639                                 if(fast_move && control.aux1)
640                                         speedV.Y = movement_speed_fast;
641                                 else
642                                         speedV.Y = movement_speed_walk;
643                         }
644                 }
645                 else if(m_can_jump)
646                 {
647                         /*
648                                 NOTE: The d value in move() affects jump height by
649                                 raising the height at which the jump speed is kept
650                                 at its starting value
651                         */
652                         v3f speedJ = getSpeed();
653                         if(speedJ.Y >= -0.5 * BS) {
654                                 if (m_ledge_detected) {
655                                         // Limit jump speed to a minimum that allows
656                                         // jumping up onto a ledge 2 nodes up.
657                                         speedJ.Y = movement_speed_jump *
658                                                         MYMAX(physics_override_jump, 1.3f);
659                                         setSpeed(speedJ);
660                                         m_ledge_detected = false;
661                                 } else {
662                                         speedJ.Y = movement_speed_jump * physics_override_jump;
663                                         setSpeed(speedJ);
664                                 }
665
666                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
667                                 m_client->event()->put(e);
668                         }
669                 }
670                 else if(in_liquid)
671                 {
672                         if(fast_climb)
673                                 speedV.Y = movement_speed_fast;
674                         else
675                                 speedV.Y = movement_speed_walk;
676                         swimming_vertical = true;
677                 }
678                 else if(is_climbing)
679                 {
680                         if(fast_climb)
681                                 speedV.Y = movement_speed_fast;
682                         else
683                                 speedV.Y = movement_speed_climb;
684                 }
685         }
686
687         // The speed of the player (Y is ignored)
688         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
689                 speedH = speedH.normalize() * movement_speed_fast;
690         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
691                 speedH = speedH.normalize() * movement_speed_crouch;
692         else
693                 speedH = speedH.normalize() * movement_speed_walk;
694
695         // Acceleration increase
696         f32 incH = 0; // Horizontal (X, Z)
697         f32 incV = 0; // Vertical (Y)
698         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
699         {
700                 // Jumping and falling
701                 if(superspeed || (fast_move && control.aux1))
702                         incH = movement_acceleration_fast * BS * dtime;
703                 else
704                         incH = movement_acceleration_air * BS * dtime;
705                 incV = 0; // No vertical acceleration in air
706         }
707         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
708                 incH = incV = movement_acceleration_fast * BS * dtime;
709         else
710                 incH = incV = movement_acceleration_default * BS * dtime;
711
712         // Accelerate to target speed with maximum increment
713         accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
714         accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
715 }
716
717 v3s16 LocalPlayer::getStandingNodePos()
718 {
719         if(m_sneak_node_exists)
720                 return m_sneak_node;
721         return floatToInt(getPosition() - v3f(0, BS, 0), BS);
722 }
723
724 v3s16 LocalPlayer::getFootstepNodePos()
725 {
726         if (in_liquid_stable)
727                 // Emit swimming sound if the player is in liquid
728                 return floatToInt(getPosition(), BS);
729         if (touching_ground)
730                 // BS * 0.05 below the player's feet ensures a 1/16th height
731                 // nodebox is detected instead of the node below it.
732                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
733         // A larger distance below is necessary for a footstep sound
734         // when landing after a jump or fall. BS * 0.5 ensures water
735         // sounds when swimming in 1 node deep water.
736         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
737 }
738
739 v3s16 LocalPlayer::getLightPosition() const
740 {
741         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
742 }
743
744 v3f LocalPlayer::getEyeOffset() const
745 {
746         float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
747         return v3f(0, BS * eye_height, 0);
748 }
749
750 // Horizontal acceleration (X and Z), Y direction is ignored
751 void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
752 {
753         if (max_increase == 0)
754                 return;
755
756         v3f d_wanted = target_speed - m_speed;
757         d_wanted.Y = 0;
758         f32 dl = d_wanted.getLength();
759         if (dl > max_increase)
760                 dl = max_increase;
761
762         v3f d = d_wanted.normalize() * dl;
763
764         m_speed.X += d.X;
765         m_speed.Z += d.Z;
766 }
767
768 // Vertical acceleration (Y), X and Z directions are ignored
769 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
770 {
771         if (max_increase == 0)
772                 return;
773
774         f32 d_wanted = target_speed.Y - m_speed.Y;
775         if (d_wanted > max_increase)
776                 d_wanted = max_increase;
777         else if (d_wanted < -max_increase)
778                 d_wanted = -max_increase;
779
780         m_speed.Y += d_wanted;
781 }
782
783 // Temporary option for old move code
784 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
785                 std::vector<CollisionInfo> *collision_info)
786 {
787         Map *map = &env->getMap();
788         INodeDefManager *nodemgr = m_client->ndef();
789
790         v3f position = getPosition();
791
792         // Copy parent position if local player is attached
793         if (isAttached) {
794                 setPosition(overridePosition);
795                 m_sneak_node_exists = false;
796                 return;
797         }
798
799         // Skip collision detection if noclip mode is used
800         bool fly_allowed = m_client->checkLocalPrivilege("fly");
801         bool noclip = m_client->checkLocalPrivilege("noclip") &&
802                 g_settings->getBool("noclip");
803         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
804         if (free_move) {
805                 position += m_speed * dtime;
806                 setPosition(position);
807                 m_sneak_node_exists = false;
808                 return;
809         }
810
811         /*
812                 Collision detection
813         */
814         bool is_valid_position;
815         MapNode node;
816         v3s16 pp;
817
818         /*
819                 Check if player is in liquid (the oscillating value)
820         */
821         if (in_liquid) {
822                 // If in liquid, the threshold of coming out is at higher y
823                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
824                 node = map->getNodeNoEx(pp, &is_valid_position);
825                 if (is_valid_position) {
826                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
827                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
828                 } else {
829                         in_liquid = false;
830                 }
831         } else {
832                 // If not in liquid, the threshold of going in is at lower y
833                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
834                 node = map->getNodeNoEx(pp, &is_valid_position);
835                 if (is_valid_position) {
836                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
837                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
838                 } else {
839                         in_liquid = false;
840                 }
841         }
842
843         /*
844                 Check if player is in liquid (the stable value)
845         */
846         pp = floatToInt(position + v3f(0, 0, 0), BS);
847         node = map->getNodeNoEx(pp, &is_valid_position);
848         if (is_valid_position)
849                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
850         else
851                 in_liquid_stable = false;
852
853         /*
854                 Check if player is climbing
855         */
856         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
857         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
858         node = map->getNodeNoEx(pp, &is_valid_position);
859         bool is_valid_position2;
860         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
861
862         if (!(is_valid_position && is_valid_position2))
863                 is_climbing = false;
864         else
865                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
866                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
867
868         /*
869                 Collision uncertainty radius
870                 Make it a bit larger than the maximum distance of movement
871         */
872         //f32 d = pos_max_d * 1.1;
873         // A fairly large value in here makes moving smoother
874         f32 d = 0.15 * BS;
875         // This should always apply, otherwise there are glitches
876         sanity_check(d > pos_max_d);
877         // Maximum distance over border for sneaking
878         f32 sneak_max = BS * 0.4;
879
880         /*
881                 If sneaking, keep in range from the last walked node and don't
882                 fall off from it
883         */
884         if (control.sneak && m_sneak_node_exists &&
885                         !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
886                         physics_override_sneak) {
887                 f32 maxd = 0.5 * BS + sneak_max;
888                 v3f lwn_f = intToFloat(m_sneak_node, BS);
889                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
890                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
891
892                 if (!is_climbing) {
893                         // Move up if necessary
894                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
895                         if (position.Y < new_y)
896                                 position.Y = new_y;
897                         /*
898                                 Collision seems broken, since player is sinking when
899                                 sneaking over the edges of current sneaking_node.
900                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
901                         */
902                         if (m_speed.Y < 0)
903                                 m_speed.Y = 0;
904                 }
905         }
906
907         // this shouldn't be hardcoded but transmitted from server
908         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
909
910 #ifdef __ANDROID__
911         player_stepheight += (0.6 * BS);
912 #endif
913
914         v3f accel_f = v3f(0, 0, 0);
915
916         collisionMoveResult result = collisionMoveSimple(env, m_client,
917                 pos_max_d, m_collisionbox, player_stepheight, dtime,
918                 &position, &m_speed, accel_f);
919
920         /*
921                 If the player's feet touch the topside of any node, this is
922                 set to true.
923
924                 Player is allowed to jump when this is true.
925         */
926         bool touching_ground_was = touching_ground;
927         touching_ground = result.touching_ground;
928
929     //bool standing_on_unloaded = result.standing_on_unloaded;
930
931         /*
932                 Check the nodes under the player to see from which node the
933                 player is sneaking from, if any.  If the node from under
934                 the player has been removed, the player falls.
935         */
936         f32 position_y_mod = 0.05 * BS;
937         if (m_sneak_node_bb_ymax > 0)
938                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
939         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
940         if (m_sneak_node_exists &&
941                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
942                         m_old_node_below_type != "air") {
943                 // Old node appears to have been removed; that is,
944                 // it wasn't air before but now it is
945                 m_need_to_get_new_sneak_node = false;
946                 m_sneak_node_exists = false;
947         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
948                 // We are on something, so make sure to recalculate the sneak
949                 // node.
950                 m_need_to_get_new_sneak_node = true;
951         }
952
953         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
954                 m_sneak_node_bb_ymax = 0;
955                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
956                 v2f player_p2df(position.X, position.Z);
957                 f32 min_distance_f = 100000.0 * BS;
958                 // If already seeking from some node, compare to it.
959                 v3s16 new_sneak_node = m_sneak_node;
960                 for (s16 x= -1; x <= 1; x++)
961                 for (s16 z= -1; z <= 1; z++) {
962                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
963                         v3f pf = intToFloat(p, BS);
964                         v2f node_p2df(pf.X, pf.Z);
965                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
966                         f32 max_axis_distance_f = MYMAX(
967                                         fabs(player_p2df.X - node_p2df.X),
968                                         fabs(player_p2df.Y - node_p2df.Y));
969
970                         if (distance_f > min_distance_f ||
971                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
972                                 continue;
973
974                         // The node to be sneaked on has to be walkable
975                         node = map->getNodeNoEx(p, &is_valid_position);
976                         if (!is_valid_position || nodemgr->get(node).walkable == false)
977                                 continue;
978                         // And the node above it has to be nonwalkable
979                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
980                         if (!is_valid_position || nodemgr->get(node).walkable)
981                                 continue;
982                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
983                         if (!physics_override_sneak_glitch) {
984                                 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
985                                 if (!is_valid_position || nodemgr->get(node).walkable)
986                                         continue;
987                         }
988
989                         min_distance_f = distance_f;
990                         new_sneak_node = p;
991                 }
992
993                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
994
995                 m_sneak_node = new_sneak_node;
996                 m_sneak_node_exists = sneak_node_found;
997
998                 if (sneak_node_found) {
999                         f32 cb_max = 0;
1000                         MapNode n = map->getNodeNoEx(m_sneak_node);
1001                         std::vector<aabb3f> nodeboxes;
1002                         n.getCollisionBoxes(nodemgr, &nodeboxes);
1003                         for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
1004                                         it != nodeboxes.end(); ++it) {
1005                                 aabb3f box = *it;
1006                                 if (box.MaxEdge.Y > cb_max)
1007                                         cb_max = box.MaxEdge.Y;
1008                         }
1009                         m_sneak_node_bb_ymax = cb_max;
1010                 }
1011
1012                 /*
1013                         If sneaking, the player's collision box can be in air, so
1014                         this has to be set explicitly
1015                 */
1016                 if (sneak_node_found && control.sneak)
1017                         touching_ground = true;
1018         }
1019
1020         /*
1021                 Set new position but keep sneak node set
1022         */
1023         bool sneak_node_exists = m_sneak_node_exists;
1024         setPosition(position);
1025         m_sneak_node_exists = sneak_node_exists;
1026
1027         /*
1028                 Report collisions
1029         */
1030         // Dont report if flying
1031         if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1032                 for (size_t i = 0; i < result.collisions.size(); i++) {
1033                         const CollisionInfo &info = result.collisions[i];
1034                         collision_info->push_back(info);
1035                 }
1036         }
1037
1038         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1039                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
1040                 m_client->event()->put(e);
1041                 // Set camera impact value to be used for view bobbing
1042                 camera_impact = getSpeed().Y * -1;
1043         }
1044
1045         {
1046                 camera_barely_in_ceiling = false;
1047                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1048                 MapNode n = map->getNodeNoEx(camera_np);
1049                 if (n.getContent() != CONTENT_IGNORE) {
1050                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1051                                 camera_barely_in_ceiling = true;
1052                 }
1053         }
1054
1055         /*
1056                 Update the node last under the player
1057         */
1058         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1059         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1060
1061         /*
1062                 Check properties of the node on which the player is standing
1063         */
1064         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1065         // Determine if jumping is possible
1066         m_can_jump = touching_ground && !in_liquid;
1067         if (itemgroup_get(f.groups, "disable_jump"))
1068                 m_can_jump = false;
1069         // Jump key pressed while jumping off from a bouncy block
1070         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1071                         m_speed.Y >= -0.5 * BS) {
1072                 float jumpspeed = movement_speed_jump * physics_override_jump;
1073                 if (m_speed.Y > 1) {
1074                         // Reduce boost when speed already is high
1075                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1076                 } else {
1077                         m_speed.Y += jumpspeed;
1078                 }
1079                 setSpeed(m_speed);
1080                 m_can_jump = false;
1081         }
1082 }