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