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