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