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