ea434720763e4d74fbf665f7821f5c469145fe9f
[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         got_teleported(false),
39         isAttached(false),
40         touching_ground(false),
41         in_liquid(false),
42         in_liquid_stable(false),
43         liquid_viscosity(0),
44         is_climbing(false),
45         swimming_vertical(false),
46         // Movement overrides are multipliers and must be 1 by default
47         physics_override_speed(1.0f),
48         physics_override_jump(1.0f),
49         physics_override_gravity(1.0f),
50         physics_override_sneak(true),
51         physics_override_sneak_glitch(true),
52         physics_override_new_move(true),  // Temporary option for old move code
53         overridePosition(v3f(0,0,0)),
54         last_position(v3f(0,0,0)),
55         last_speed(v3f(0,0,0)),
56         last_pitch(0),
57         last_yaw(0),
58         last_keyPressed(0),
59         last_camera_fov(0),
60         last_wanted_range(0),
61         camera_impact(0.f),
62         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 && !got_teleported) {
309                 v3f sn_f = intToFloat(m_sneak_node, BS);
310                 const v3f bmin = m_sneak_node_bb_top.MinEdge;
311                 const v3f bmax = m_sneak_node_bb_top.MaxEdge;
312
313                 position.X = rangelim(position.X,
314                                 sn_f.X+bmin.X - sneak_max.X, sn_f.X+bmax.X + sneak_max.X);
315                 position.Z = rangelim(position.Z,
316                                 sn_f.Z+bmin.Z - sneak_max.Z, sn_f.Z+bmax.Z + sneak_max.Z);
317
318                 // Because we keep the player collision box on the node, limiting
319                 // position.Y is not necessary but useful to prevent players from
320                 // being inside a node if sneaking on e.g. the lower part of a stair
321                 if (!m_sneak_ladder_detected) {
322                         position.Y = MYMAX(position.Y, sn_f.Y+bmax.Y);
323                 } else {
324                         // legacy behaviour that sometimes causes some weird slow sinking
325                         m_speed.Y = MYMAX(m_speed.Y, 0);
326                 }
327         }
328
329         if (got_teleported)
330                 got_teleported = false;
331
332         // TODO: this shouldn't be hardcoded but transmitted from server
333         float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
334
335 #ifdef __ANDROID__
336         player_stepheight += (0.6 * BS);
337 #endif
338
339         v3f accel_f = v3f(0,0,0);
340
341         collisionMoveResult result = collisionMoveSimple(env, m_client,
342                 pos_max_d, m_collisionbox, player_stepheight, dtime,
343                 &position, &m_speed, accel_f);
344
345         /*
346                 If the player's feet touch the topside of any node, this is
347                 set to true.
348
349                 Player is allowed to jump when this is true.
350         */
351         bool touching_ground_was = touching_ground;
352         touching_ground = result.touching_ground;
353
354         // We want the top of the sneak node to be below the players feet
355         f32 position_y_mod;
356         if (m_sneak_node_exists)
357                 position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
358         else
359                 position_y_mod = (0.5 - 0.05) * BS;
360         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
361         /*
362                 Check the nodes under the player to see from which node the
363                 player is sneaking from, if any.  If the node from under
364                 the player has been removed, the player falls.
365         */
366         if (m_sneak_node_exists &&
367                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
368                         m_old_node_below_type != "air") {
369                 // Old node appears to have been removed; that is,
370                 // it wasn't air before but now it is
371                 m_need_to_get_new_sneak_node = false;
372                 m_sneak_node_exists = false;
373         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
374                 // We are on something, so make sure to recalculate the sneak
375                 // node.
376                 m_need_to_get_new_sneak_node = true;
377         }
378
379         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
380                 v2f player_p2df(position.X, position.Z);
381                 f32 min_distance_f = 100000.0 * BS;
382                 v3s16 new_sneak_node = m_sneak_node;
383                 for(s16 x=-1; x<=1; x++)
384                 for(s16 z=-1; z<=1; z++)
385                 {
386                         v3s16 p = current_node + v3s16(x,0,z);
387                         v3f pf = intToFloat(p, BS);
388                         v2f node_p2df(pf.X, pf.Z);
389                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
390
391                         if (distance_f > min_distance_f ||
392                                         fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
393                                         fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
394                                 continue;
395
396
397                         // The node to be sneaked on has to be walkable
398                         node = map->getNodeNoEx(p, &is_valid_position);
399                         if (!is_valid_position || !nodemgr->get(node).walkable)
400                                 continue;
401                         // And the node(s) above have to be nonwalkable
402                         bool ok = true;
403                         if (!physics_override_sneak_glitch) {
404                                 u16 height = ceilf(
405                                                 (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
406                                 );
407                                 for (u16 y = 1; y <= height; y++) {
408                                         node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
409                                         if (!is_valid_position || nodemgr->get(node).walkable) {
410                                                 ok = false;
411                                                 break;
412                                         }
413                                 }
414                         } else {
415                                 // legacy behaviour: check just one node
416                                 node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
417                                 ok = is_valid_position && !nodemgr->get(node).walkable;
418                         }
419                         if (!ok)
420                                 continue;
421
422                         min_distance_f = distance_f;
423                         new_sneak_node = p;
424                 }
425
426                 bool sneak_node_found = (min_distance_f < 100000.0 * BS);
427                 m_sneak_node = new_sneak_node;
428                 m_sneak_node_exists = sneak_node_found;
429
430                 if (sneak_node_found) {
431                         // Update saved top bounding box of sneak node
432                         MapNode n = map->getNodeNoEx(m_sneak_node);
433                         std::vector<aabb3f> nodeboxes;
434                         n.getCollisionBoxes(nodemgr, &nodeboxes);
435                         m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
436
437                         m_sneak_ladder_detected = physics_override_sneak_glitch &&
438                                         detectSneakLadder(map, nodemgr, floatToInt(position, BS));
439                 } else {
440                         m_sneak_ladder_detected = false;
441                 }
442         }
443
444         /*
445                 If 'sneak glitch' enabled detect ledge for old sneak-jump
446                 behaviour of climbing onto a ledge 2 nodes up.
447         */
448         if (physics_override_sneak_glitch && control.sneak && control.jump)
449                 m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
450
451         /*
452                 Set new position
453         */
454         setPosition(position);
455
456         /*
457                 Report collisions
458         */
459
460         // Dont report if flying
461         if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
462                 for(size_t i=0; i<result.collisions.size(); i++) {
463                         const CollisionInfo &info = result.collisions[i];
464                         collision_info->push_back(info);
465                 }
466         }
467
468         if(!result.standing_on_object && !touching_ground_was && touching_ground) {
469                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
470                 m_client->event()->put(e);
471
472                 // Set camera impact value to be used for view bobbing
473                 camera_impact = getSpeed().Y * -1;
474         }
475
476         {
477                 camera_barely_in_ceiling = false;
478                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
479                 MapNode n = map->getNodeNoEx(camera_np);
480                 if(n.getContent() != CONTENT_IGNORE){
481                         if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
482                                 camera_barely_in_ceiling = true;
483                         }
484                 }
485         }
486
487         /*
488                 Update the node last under the player
489         */
490         m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
491         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
492
493         /*
494                 Check properties of the node on which the player is standing
495         */
496         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
497         // Determine if jumping is possible
498         m_can_jump = touching_ground && !in_liquid;
499         if (itemgroup_get(f.groups, "disable_jump"))
500                 m_can_jump = false;
501         else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
502                 m_can_jump = true;
503
504         // Jump key pressed while jumping off from a bouncy block
505         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
506                 m_speed.Y >= -0.5 * BS) {
507                 float jumpspeed = movement_speed_jump * physics_override_jump;
508                 if (m_speed.Y > 1) {
509                         // Reduce boost when speed already is high
510                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
511                 } else {
512                         m_speed.Y += jumpspeed;
513                 }
514                 setSpeed(m_speed);
515                 m_can_jump = false;
516         }
517 }
518
519 void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d)
520 {
521         move(dtime, env, pos_max_d, NULL);
522 }
523
524 void LocalPlayer::applyControl(float dtime)
525 {
526         // Clear stuff
527         swimming_vertical = false;
528
529         setPitch(control.pitch);
530         setYaw(control.yaw);
531
532         // Nullify speed and don't run positioning code if the player is attached
533         if(isAttached)
534         {
535                 setSpeed(v3f(0,0,0));
536                 return;
537         }
538
539         v3f move_direction = v3f(0,0,1);
540         move_direction.rotateXZBy(getYaw());
541
542         v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
543         v3f speedV = v3f(0,0,0); // Vertical (Y)
544
545         bool fly_allowed = m_client->checkLocalPrivilege("fly");
546         bool fast_allowed = m_client->checkLocalPrivilege("fast");
547
548         bool free_move = fly_allowed && g_settings->getBool("free_move");
549         bool fast_move = fast_allowed && g_settings->getBool("fast_move");
550         // When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
551         bool fast_climb = fast_move && control.aux1 && !g_settings->getBool("aux1_descends");
552         bool continuous_forward = g_settings->getBool("continuous_forward");
553         bool always_fly_fast = g_settings->getBool("always_fly_fast");
554
555         // Whether superspeed mode is used or not
556         bool superspeed = false;
557
558         if (always_fly_fast && free_move && fast_move)
559                 superspeed = true;
560
561         // Old descend control
562         if(g_settings->getBool("aux1_descends"))
563         {
564                 // If free movement and fast movement, always move fast
565                 if(free_move && fast_move)
566                         superspeed = true;
567
568                 // Auxiliary button 1 (E)
569                 if(control.aux1)
570                 {
571                         if(free_move)
572                         {
573                                 // In free movement mode, aux1 descends
574                                 if(fast_move)
575                                         speedV.Y = -movement_speed_fast;
576                                 else
577                                         speedV.Y = -movement_speed_walk;
578                         }
579                         else if(in_liquid || in_liquid_stable)
580                         {
581                                 speedV.Y = -movement_speed_walk;
582                                 swimming_vertical = true;
583                         }
584                         else if(is_climbing)
585                         {
586                                 speedV.Y = -movement_speed_climb;
587                         }
588                         else
589                         {
590                                 // If not free movement but fast is allowed, aux1 is
591                                 // "Turbo button"
592                                 if(fast_move)
593                                         superspeed = true;
594                         }
595                 }
596         }
597         // New minecraft-like descend control
598         else
599         {
600                 // Auxiliary button 1 (E)
601                 if(control.aux1)
602                 {
603                         if(!is_climbing)
604                         {
605                                 // aux1 is "Turbo button"
606                                 if(fast_move)
607                                         superspeed = true;
608                         }
609                 }
610
611                 if(control.sneak)
612                 {
613                         if(free_move)
614                         {
615                                 // In free movement mode, sneak descends
616                                 if (fast_move && (control.aux1 || always_fly_fast))
617                                         speedV.Y = -movement_speed_fast;
618                                 else
619                                         speedV.Y = -movement_speed_walk;
620                         }
621                         else if(in_liquid || in_liquid_stable)
622                         {
623                                 if(fast_climb)
624                                         speedV.Y = -movement_speed_fast;
625                                 else
626                                         speedV.Y = -movement_speed_walk;
627                                 swimming_vertical = true;
628                         }
629                         else if(is_climbing)
630                         {
631                                 if(fast_climb)
632                                         speedV.Y = -movement_speed_fast;
633                                 else
634                                         speedV.Y = -movement_speed_climb;
635                         }
636                 }
637         }
638
639         if (continuous_forward)
640                 speedH += move_direction;
641
642         if (control.up) {
643                 if (continuous_forward) {
644                         if (fast_move)
645                                 superspeed = true;
646                 } else {
647                         speedH += move_direction;
648                 }
649         }
650         if (control.down) {
651                 speedH -= move_direction;
652         }
653         if (!control.up && !control.down) {
654                 speedH -= move_direction *
655                         (control.forw_move_joystick_axis / 32767.f);
656         }
657         if (control.left) {
658                 speedH += move_direction.crossProduct(v3f(0,1,0));
659         }
660         if (control.right) {
661                 speedH += move_direction.crossProduct(v3f(0,-1,0));
662         }
663         if (!control.left && !control.right) {
664                 speedH -= move_direction.crossProduct(v3f(0,1,0)) *
665                         (control.sidew_move_joystick_axis / 32767.f);
666         }
667         if(control.jump)
668         {
669                 if (free_move) {
670                         if (g_settings->getBool("aux1_descends") || always_fly_fast) {
671                                 if (fast_move)
672                                         speedV.Y = movement_speed_fast;
673                                 else
674                                         speedV.Y = movement_speed_walk;
675                         } else {
676                                 if(fast_move && control.aux1)
677                                         speedV.Y = movement_speed_fast;
678                                 else
679                                         speedV.Y = movement_speed_walk;
680                         }
681                 }
682                 else if(m_can_jump)
683                 {
684                         /*
685                                 NOTE: The d value in move() affects jump height by
686                                 raising the height at which the jump speed is kept
687                                 at its starting value
688                         */
689                         v3f speedJ = getSpeed();
690                         if(speedJ.Y >= -0.5 * BS) {
691                                 if (m_ledge_detected) {
692                                         // Limit jump speed to a minimum that allows
693                                         // jumping up onto a ledge 2 nodes up.
694                                         speedJ.Y = movement_speed_jump *
695                                                         MYMAX(physics_override_jump, 1.3f);
696                                         setSpeed(speedJ);
697                                         m_ledge_detected = false;
698                                 } else {
699                                         speedJ.Y = movement_speed_jump * physics_override_jump;
700                                         setSpeed(speedJ);
701                                 }
702
703                                 MtEvent *e = new SimpleTriggerEvent("PlayerJump");
704                                 m_client->event()->put(e);
705                         }
706                 }
707                 else if(in_liquid)
708                 {
709                         if(fast_climb)
710                                 speedV.Y = movement_speed_fast;
711                         else
712                                 speedV.Y = movement_speed_walk;
713                         swimming_vertical = true;
714                 }
715                 else if(is_climbing)
716                 {
717                         if(fast_climb)
718                                 speedV.Y = movement_speed_fast;
719                         else
720                                 speedV.Y = movement_speed_climb;
721                 }
722         }
723
724         // The speed of the player (Y is ignored)
725         if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
726                 speedH = speedH.normalize() * movement_speed_fast;
727         else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
728                 speedH = speedH.normalize() * movement_speed_crouch;
729         else
730                 speedH = speedH.normalize() * movement_speed_walk;
731
732         // Acceleration increase
733         f32 incH = 0; // Horizontal (X, Z)
734         f32 incV = 0; // Vertical (Y)
735         if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
736         {
737                 // Jumping and falling
738                 if(superspeed || (fast_move && control.aux1))
739                         incH = movement_acceleration_fast * BS * dtime;
740                 else
741                         incH = movement_acceleration_air * BS * dtime;
742                 incV = 0; // No vertical acceleration in air
743         }
744         else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
745                 incH = incV = movement_acceleration_fast * BS * dtime;
746         else
747                 incH = incV = movement_acceleration_default * BS * dtime;
748
749         // Accelerate to target speed with maximum increment
750         accelerateHorizontal(speedH * physics_override_speed, incH * physics_override_speed);
751         accelerateVertical(speedV * physics_override_speed, incV * physics_override_speed);
752 }
753
754 v3s16 LocalPlayer::getStandingNodePos()
755 {
756         if(m_sneak_node_exists)
757                 return m_sneak_node;
758         return floatToInt(getPosition() - v3f(0, BS, 0), BS);
759 }
760
761 v3s16 LocalPlayer::getFootstepNodePos()
762 {
763         if (touching_ground)
764                 // BS * 0.05 below the player's feet ensures a 1/16th height
765                 // nodebox is detected instead of the node below it.
766                 return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
767         // A larger distance below is necessary for a footstep sound
768         // when landing after a jump or fall. BS * 0.5 ensures water
769         // sounds when swimming in 1 node deep water.
770         return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
771 }
772
773 v3s16 LocalPlayer::getLightPosition() const
774 {
775         return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
776 }
777
778 v3f LocalPlayer::getEyeOffset() const
779 {
780         float eye_height = camera_barely_in_ceiling ? 1.5f : 1.625f;
781         return v3f(0, BS * eye_height, 0);
782 }
783
784 // Horizontal acceleration (X and Z), Y direction is ignored
785 void LocalPlayer::accelerateHorizontal(const v3f &target_speed, const f32 max_increase)
786 {
787         if (max_increase == 0)
788                 return;
789
790         v3f d_wanted = target_speed - m_speed;
791         d_wanted.Y = 0;
792         f32 dl = d_wanted.getLength();
793         if (dl > max_increase)
794                 dl = max_increase;
795
796         v3f d = d_wanted.normalize() * dl;
797
798         m_speed.X += d.X;
799         m_speed.Z += d.Z;
800 }
801
802 // Vertical acceleration (Y), X and Z directions are ignored
803 void LocalPlayer::accelerateVertical(const v3f &target_speed, const f32 max_increase)
804 {
805         if (max_increase == 0)
806                 return;
807
808         f32 d_wanted = target_speed.Y - m_speed.Y;
809         if (d_wanted > max_increase)
810                 d_wanted = max_increase;
811         else if (d_wanted < -max_increase)
812                 d_wanted = -max_increase;
813
814         m_speed.Y += d_wanted;
815 }
816
817 // Temporary option for old move code
818 void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
819                 std::vector<CollisionInfo> *collision_info)
820 {
821         Map *map = &env->getMap();
822         INodeDefManager *nodemgr = m_client->ndef();
823
824         v3f position = getPosition();
825
826         // Copy parent position if local player is attached
827         if (isAttached) {
828                 setPosition(overridePosition);
829                 m_sneak_node_exists = false;
830                 return;
831         }
832
833         // Skip collision detection if noclip mode is used
834         bool fly_allowed = m_client->checkLocalPrivilege("fly");
835         bool noclip = m_client->checkLocalPrivilege("noclip") &&
836                 g_settings->getBool("noclip");
837         bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
838         if (free_move) {
839                 position += m_speed * dtime;
840                 setPosition(position);
841                 m_sneak_node_exists = false;
842                 return;
843         }
844
845         /*
846                 Collision detection
847         */
848         bool is_valid_position;
849         MapNode node;
850         v3s16 pp;
851
852         /*
853                 Check if player is in liquid (the oscillating value)
854         */
855         if (in_liquid) {
856                 // If in liquid, the threshold of coming out is at higher y
857                 pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
858                 node = map->getNodeNoEx(pp, &is_valid_position);
859                 if (is_valid_position) {
860                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
861                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
862                 } else {
863                         in_liquid = false;
864                 }
865         } else {
866                 // If not in liquid, the threshold of going in is at lower y
867                 pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
868                 node = map->getNodeNoEx(pp, &is_valid_position);
869                 if (is_valid_position) {
870                         in_liquid = nodemgr->get(node.getContent()).isLiquid();
871                         liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
872                 } else {
873                         in_liquid = false;
874                 }
875         }
876
877         /*
878                 Check if player is in liquid (the stable value)
879         */
880         pp = floatToInt(position + v3f(0, 0, 0), BS);
881         node = map->getNodeNoEx(pp, &is_valid_position);
882         if (is_valid_position)
883                 in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
884         else
885                 in_liquid_stable = false;
886
887         /*
888                 Check if player is climbing
889         */
890         pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
891         v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
892         node = map->getNodeNoEx(pp, &is_valid_position);
893         bool is_valid_position2;
894         MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
895
896         if (!(is_valid_position && is_valid_position2))
897                 is_climbing = false;
898         else
899                 is_climbing = (nodemgr->get(node.getContent()).climbable ||
900                                 nodemgr->get(node2.getContent()).climbable) && !free_move;
901
902         /*
903                 Collision uncertainty radius
904                 Make it a bit larger than the maximum distance of movement
905         */
906         //f32 d = pos_max_d * 1.1;
907         // A fairly large value in here makes moving smoother
908         f32 d = 0.15 * BS;
909         // This should always apply, otherwise there are glitches
910         sanity_check(d > pos_max_d);
911         // Maximum distance over border for sneaking
912         f32 sneak_max = BS * 0.4;
913
914         /*
915                 If sneaking, keep in range from the last walked node and don't
916                 fall off from it
917         */
918         if (control.sneak && m_sneak_node_exists &&
919                         !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid &&
920                         physics_override_sneak && !got_teleported) {
921                 f32 maxd = 0.5 * BS + sneak_max;
922                 v3f lwn_f = intToFloat(m_sneak_node, BS);
923                 position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
924                 position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
925
926                 if (!is_climbing) {
927                         // Move up if necessary
928                         f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
929                         if (position.Y < new_y)
930                                 position.Y = new_y;
931                         /*
932                                 Collision seems broken, since player is sinking when
933                                 sneaking over the edges of current sneaking_node.
934                                 TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
935                         */
936                         if (m_speed.Y < 0)
937                                 m_speed.Y = 0;
938                 }
939         }
940
941         if (got_teleported)
942                 got_teleported = false;
943
944         // this shouldn't be hardcoded but transmitted from server
945         float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
946
947 #ifdef __ANDROID__
948         player_stepheight += (0.6 * BS);
949 #endif
950
951         v3f accel_f = v3f(0, 0, 0);
952
953         collisionMoveResult result = collisionMoveSimple(env, m_client,
954                 pos_max_d, m_collisionbox, player_stepheight, dtime,
955                 &position, &m_speed, accel_f);
956
957         /*
958                 If the player's feet touch the topside of any node, this is
959                 set to true.
960
961                 Player is allowed to jump when this is true.
962         */
963         bool touching_ground_was = touching_ground;
964         touching_ground = result.touching_ground;
965
966     //bool standing_on_unloaded = result.standing_on_unloaded;
967
968         /*
969                 Check the nodes under the player to see from which node the
970                 player is sneaking from, if any.  If the node from under
971                 the player has been removed, the player falls.
972         */
973         f32 position_y_mod = 0.05 * BS;
974         if (m_sneak_node_bb_ymax > 0)
975                 position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
976         v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
977         if (m_sneak_node_exists &&
978                         nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
979                         m_old_node_below_type != "air") {
980                 // Old node appears to have been removed; that is,
981                 // it wasn't air before but now it is
982                 m_need_to_get_new_sneak_node = false;
983                 m_sneak_node_exists = false;
984         } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
985                 // We are on something, so make sure to recalculate the sneak
986                 // node.
987                 m_need_to_get_new_sneak_node = true;
988         }
989
990         if (m_need_to_get_new_sneak_node && physics_override_sneak) {
991                 m_sneak_node_bb_ymax = 0;
992                 v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
993                 v2f player_p2df(position.X, position.Z);
994                 f32 min_distance_f = 100000.0 * BS;
995                 // If already seeking from some node, compare to it.
996                 v3s16 new_sneak_node = m_sneak_node;
997                 for (s16 x= -1; x <= 1; x++)
998                 for (s16 z= -1; z <= 1; z++) {
999                         v3s16 p = pos_i_bottom + v3s16(x, 0, z);
1000                         v3f pf = intToFloat(p, BS);
1001                         v2f node_p2df(pf.X, pf.Z);
1002                         f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
1003                         f32 max_axis_distance_f = MYMAX(
1004                                         fabs(player_p2df.X - node_p2df.X),
1005                                         fabs(player_p2df.Y - node_p2df.Y));
1006
1007                         if (distance_f > min_distance_f ||
1008                                         max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
1009                                 continue;
1010
1011                         // The node to be sneaked on has to be walkable
1012                         node = map->getNodeNoEx(p, &is_valid_position);
1013                         if (!is_valid_position || nodemgr->get(node).walkable == false)
1014                                 continue;
1015                         // And the node above it has to be nonwalkable
1016                         node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
1017                         if (!is_valid_position || nodemgr->get(node).walkable)
1018                                 continue;
1019                         // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
1020                         if (!physics_override_sneak_glitch) {
1021                                 node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
1022                                 if (!is_valid_position || nodemgr->get(node).walkable)
1023                                         continue;
1024                         }
1025
1026                         min_distance_f = distance_f;
1027                         new_sneak_node = p;
1028                 }
1029
1030                 bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
1031
1032                 m_sneak_node = new_sneak_node;
1033                 m_sneak_node_exists = sneak_node_found;
1034
1035                 if (sneak_node_found) {
1036                         f32 cb_max = 0;
1037                         MapNode n = map->getNodeNoEx(m_sneak_node);
1038                         std::vector<aabb3f> nodeboxes;
1039                         n.getCollisionBoxes(nodemgr, &nodeboxes);
1040                         for (std::vector<aabb3f>::iterator it = nodeboxes.begin();
1041                                         it != nodeboxes.end(); ++it) {
1042                                 aabb3f box = *it;
1043                                 if (box.MaxEdge.Y > cb_max)
1044                                         cb_max = box.MaxEdge.Y;
1045                         }
1046                         m_sneak_node_bb_ymax = cb_max;
1047                 }
1048
1049                 /*
1050                         If sneaking, the player's collision box can be in air, so
1051                         this has to be set explicitly
1052                 */
1053                 if (sneak_node_found && control.sneak)
1054                         touching_ground = true;
1055         }
1056
1057         /*
1058                 Set new position
1059         */
1060         setPosition(position);
1061
1062         /*
1063                 Report collisions
1064         */
1065         // Dont report if flying
1066         if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
1067                 for (size_t i = 0; i < result.collisions.size(); i++) {
1068                         const CollisionInfo &info = result.collisions[i];
1069                         collision_info->push_back(info);
1070                 }
1071         }
1072
1073         if (!result.standing_on_object && !touching_ground_was && touching_ground) {
1074                 MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
1075                 m_client->event()->put(e);
1076                 // Set camera impact value to be used for view bobbing
1077                 camera_impact = getSpeed().Y * -1;
1078         }
1079
1080         {
1081                 camera_barely_in_ceiling = false;
1082                 v3s16 camera_np = floatToInt(getEyePosition(), BS);
1083                 MapNode n = map->getNodeNoEx(camera_np);
1084                 if (n.getContent() != CONTENT_IGNORE) {
1085                         if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
1086                                 camera_barely_in_ceiling = true;
1087                 }
1088         }
1089
1090         /*
1091                 Update the node last under the player
1092         */
1093         m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
1094         m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
1095
1096         /*
1097                 Check properties of the node on which the player is standing
1098         */
1099         const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
1100         // Determine if jumping is possible
1101         m_can_jump = touching_ground && !in_liquid;
1102         if (itemgroup_get(f.groups, "disable_jump"))
1103                 m_can_jump = false;
1104         // Jump key pressed while jumping off from a bouncy block
1105         if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
1106                         m_speed.Y >= -0.5 * BS) {
1107                 float jumpspeed = movement_speed_jump * physics_override_jump;
1108                 if (m_speed.Y > 1) {
1109                         // Reduce boost when speed already is high
1110                         m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
1111                 } else {
1112                         m_speed.Y += jumpspeed;
1113                 }
1114                 setSpeed(m_speed);
1115                 m_can_jump = false;
1116         }
1117 }